blob: 098e02f10e54fedecccf6dcdc467ebabbf140fb5 [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
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700282 // that need to be updated 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 Radoslavov67b3ef32013-04-03 02:44:48 -0700325 IFlowPath flowObj =
326 conn.utils().getFlowPathByFlowEntry(conn,
327 flowEntryObj);
328 if (flowObj == null)
329 continue; // Should NOT happen
330
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700331 // Code for measurement purpose
332 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700333 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700334 processed_measurement_flow = true;
335 }
336 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700337
338 //
339 // TODO: Eliminate the re-fetching of flowEntryId,
340 // userState, switchState, and dpid from the flowEntryObj.
341 //
342 FlowEntryId flowEntryId =
343 new FlowEntryId(flowEntryObj.getFlowEntryId());
344 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
345 String userState = flowEntryObj.getUserState();
346 String switchState = flowEntryObj.getSwitchState();
347 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000348 if (mySwitch == null)
349 continue; // Shouldn't happen
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800350
351 //
352 // Create the Open Flow Flow Modification Entry to push
353 //
354 OFFlowMod fm =
355 (OFFlowMod) floodlightProvider.getOFMessageFactory()
356 .getMessage(OFType.FLOW_MOD);
357 long cookie = flowEntryId.value();
358
359 short flowModCommand = OFFlowMod.OFPFC_ADD;
360 if (userState.equals("FE_USER_ADD")) {
361 flowModCommand = OFFlowMod.OFPFC_ADD;
362 } else if (userState.equals("FE_USER_MODIFY")) {
363 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
364 } else if (userState.equals("FE_USER_DELETE")) {
365 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
366 } else {
367 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700368 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
369 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800370 continue;
371 }
372
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700373 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700374 // Fetch the match conditions.
375 //
376 // NOTE: The Flow matching conditions common for all
377 // Flow Entries are used ONLY if a Flow Entry does NOT
378 // have the corresponding matching condition set.
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700379 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800380 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700381 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700382 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700383 Short matchInPort = flowEntryObj.getMatchInPort();
384 if (matchInPort != null) {
385 match.setInputPort(matchInPort);
386 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
387 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700388 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700389 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700390 if (matchEthernetFrameType == null)
391 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700392 if (matchEthernetFrameType != null) {
393 match.setDataLayerType(matchEthernetFrameType);
394 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
395 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700396 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700397 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700398 if (matchSrcIPv4Net == null)
399 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700400 if (matchSrcIPv4Net != null) {
401 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
402 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700403 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700404 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700405 if (matchDstIPv4Net == null)
406 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700407 if (matchDstIPv4Net != null) {
408 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
409 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700410 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700411 String matchSrcMac = flowEntryObj.getMatchSrcMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700412 if (matchSrcMac == null)
413 matchSrcMac = flowObj.getMatchSrcMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700414 if (matchSrcMac != null) {
415 match.setDataLayerSource(matchSrcMac);
416 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
417 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700418 //
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700419 String matchDstMac = flowEntryObj.getMatchDstMac();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700420 if (matchDstMac == null)
421 matchDstMac = flowObj.getMatchDstMac();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700422 if (matchDstMac != null) {
423 match.setDataLayerDestination(matchDstMac);
424 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
425 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700426
427 //
428 // Fetch the actions
429 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800430 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700431 Short actionOutputPort = flowEntryObj.getActionOutput();
432 if (actionOutputPort != null) {
433 OFActionOutput action = new OFActionOutput();
434 // XXX: The max length is hard-coded for now
435 action.setMaxLength((short)0xffff);
436 action.setPort(actionOutputPort);
437 actions.add(action);
438 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439
440 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
441 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700442 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800443 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
444 .setCookie(cookie)
445 .setCommand(flowModCommand)
446 .setMatch(match)
447 .setActions(actions)
448 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700449 fm.setOutPort(OFPort.OFPP_NONE.getValue());
450 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
451 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
452 if (actionOutputPort != null)
453 fm.setOutPort(actionOutputPort);
454 }
455
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800456 //
457 // TODO: Set the following flag
458 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
459 // See method ForwardingBase::pushRoute()
460 //
461 try {
462 messageDamper.write(mySwitch, fm, null);
463 mySwitch.flush();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000464 //
465 // TODO: We should use the OpenFlow Barrier mechanism
466 // to check for errors, and update the SwitchState
467 // for a flow entry after the Barrier message is
468 // is received.
469 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800470 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
471 if (userState.equals("FE_USER_DELETE")) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000472 // An entry that needs to be deleted.
473 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800474 }
475 } catch (IOException e) {
476 log.error("Failure writing flow mod from network map", e);
477 }
478 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000479
480 //
481 // Delete all entries marked for deletion
482 //
483 // TODO: We should use the OpenFlow Barrier mechanism
484 // to check for errors, and delete the Flow Entries after the
485 // Barrier message is received.
486 //
487 while (! deleteFlowEntries.isEmpty()) {
488 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
489 IFlowPath flowObj =
490 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
491 if (flowObj == null) {
492 log.debug("Did not find FlowPath to be deleted");
493 continue;
494 }
495 flowObj.removeFlowEntry(flowEntryObj);
496 conn.utils().removeFlowEntry(conn, flowEntryObj);
497
498 // Test whether the last flow entry
499 Iterable<IFlowEntry> tmpflowEntries =
500 flowObj.getFlowEntries();
501 boolean found = false;
502 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
503 found = true;
504 break;
505 }
506 if (! found) {
507 // Remove the Flow Path as well
508 conn.utils().removeFlowPath(conn, flowObj);
509 }
510 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700511
512
513 //
514 // Fetch and recompute the Shortest Path for those
515 // Flow Paths this controller is responsible for.
516 //
517
518 /*
519 * TODO: For now, the computation of the reconciliation is
520 * commented-out.
521 */
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700522 topoRouteService.prepareShortestPathTopo();
523 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
524 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
525 for (IFlowPath flowPathObj : allFlowPaths) {
526 if (flowPathObj == null)
527 continue;
528 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
529 if (dataPathSummaryStr == null)
530 continue; // Could be invalid entry?
531 if (dataPathSummaryStr.isEmpty())
532 continue; // No need to maintain this flow
533
534 // Fetch the fields needed to recompute the shortest path
535 String flowIdStr = flowPathObj.getFlowId();
536 String srcDpidStr = flowPathObj.getSrcSwitch();
537 Short srcPortShort = flowPathObj.getSrcPort();
538 String dstDpidStr = flowPathObj.getDstSwitch();
539 Short dstPortShort = flowPathObj.getDstPort();
540 if ((flowIdStr == null) ||
541 (srcDpidStr == null) ||
542 (srcPortShort == null) ||
543 (dstDpidStr == null) ||
544 (dstPortShort == null)) {
545 log.debug("IGNORING Flow Path entry with null fields");
546 continue;
547 }
548
549 FlowId flowId = new FlowId(flowIdStr);
550 Dpid srcDpid = new Dpid(srcDpidStr);
551 Port srcPort = new Port(srcPortShort);
552 Dpid dstDpid = new Dpid(dstDpidStr);
553 Port dstPort = new Port(dstPortShort);
554 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
555 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700556 //
557 // NOTE: Using here the regular getShortestPath() method
558 // won't work here, because that method calls internally
559 // "conn.endTx(Transaction.COMMIT)", and that will
560 // invalidate all handlers to the Titan database.
561 // If we want to experiment with calling here
562 // getShortestPath(), we need to refactor that code
563 // to avoid closing the transaction.
564 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700565 DataPath dataPath =
566 topoRouteService.getTopoShortestPath(srcSwitchPort,
567 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000568 if (dataPath == null) {
569 // We need the DataPath to compare the paths
570 dataPath = new DataPath();
571 dataPath.setSrcPort(srcSwitchPort);
572 dataPath.setDstPort(dstSwitchPort);
573 }
574
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700575 String newDataPathSummaryStr = dataPath.dataPathSummary();
576 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
577 continue; // Nothing changed
578
579 //
580 // Use the source DPID as a heuristic to decide
581 // which controller is responsible for maintaining the
582 // shortest path.
583 // NOTE: This heuristic is error-prone: if the switch
584 // goes away and no controller is responsible for that
585 // switch, then the original Flow Path is not cleaned-up
586 //
587 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
588 if (mySwitch == null)
589 continue; // Ignore: not my responsibility
590
591 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
592 flowId.toString());
593 flowObjSet.add(flowPathObj);
594 }
595 reconcileFlows(flowObjSet);
596 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700597
598
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800599 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700600
601 if (processed_measurement_flow) {
602 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
603 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
604 (double)estimatedTime / 1000000000 + " sec";
605 log.debug(logMsg);
606 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800607 }
608 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700609
610 /*
611 final ScheduledFuture<?> measureShortestPathHandle =
612 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
613 */
614
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700615 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700616 final ScheduledFuture<?> measureMapReaderHandle =
617 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
Pavlin Radoslavove38319c2013-03-21 16:20:00 -0700618 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700619
620 final ScheduledFuture<?> mapReaderHandle =
621 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800622
623 @Override
624 public void init(String conf) {
625 conn = GraphDBConnection.getInstance(conf);
626 }
627
628 public void finalize() {
629 close();
630 }
631
632 @Override
633 public void close() {
634 conn.close();
635 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800636
637 @Override
638 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
639 Collection<Class<? extends IFloodlightService>> l =
640 new ArrayList<Class<? extends IFloodlightService>>();
641 l.add(IFlowService.class);
642 return l;
643 }
644
645 @Override
646 public Map<Class<? extends IFloodlightService>, IFloodlightService>
647 getServiceImpls() {
648 Map<Class<? extends IFloodlightService>,
649 IFloodlightService> m =
650 new HashMap<Class<? extends IFloodlightService>,
651 IFloodlightService>();
652 m.put(IFlowService.class, this);
653 return m;
654 }
655
656 @Override
657 public Collection<Class<? extends IFloodlightService>>
658 getModuleDependencies() {
659 Collection<Class<? extends IFloodlightService>> l =
660 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800661 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700662 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800663 l.add(IRestApiService.class);
664 return l;
665 }
666
667 @Override
668 public void init(FloodlightModuleContext context)
669 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700670 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800671 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700672 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800673 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800674 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
675 EnumSet.of(OFType.FLOW_MOD),
676 OFMESSAGE_DAMPER_TIMEOUT);
677 // TODO: An ugly hack!
678 String conf = "/tmp/cassandra.titan";
679 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800680 }
681
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000682 private long getNextFlowEntryId() {
683 //
684 // Generate the next Flow Entry ID.
685 // NOTE: For now, the higher 32 bits are random, and
686 // the lower 32 bits are sequential.
687 // In the future, we need a better allocation mechanism.
688 //
689 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
690 nextFlowEntryIdPrefix = randomGenerator.nextInt();
691 nextFlowEntryIdSuffix = 0;
692 } else {
693 nextFlowEntryIdSuffix++;
694 }
695 long result = (long)nextFlowEntryIdPrefix << 32;
696 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
697 return result;
698 }
699
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800700 @Override
701 public void startUp(FloodlightModuleContext context) {
702 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700703
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000704 // Initialize the Flow Entry ID generator
705 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800706 }
707
708 /**
709 * Add a flow.
710 *
711 * Internally, ONOS will automatically register the installer for
712 * receiving Flow Path Notifications for that path.
713 *
714 * @param flowPath the Flow Path to install.
715 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700716 * @param dataPathSummaryStr the data path summary string if the added
717 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800718 * @return true on success, otherwise false.
719 */
720 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700721 public boolean addFlow(FlowPath flowPath, FlowId flowId,
722 String dataPathSummaryStr) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700723 if (flowPath.flowId().value() == measurementFlowId) {
724 modifiedMeasurementFlowTime = System.nanoTime();
725 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800726
727 //
728 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700729 // Right now every new flow entry gets a new flow entry ID
730 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800731 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800732 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000733 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800734 flowEntry.setFlowEntryId(new FlowEntryId(id));
735 }
736
737 IFlowPath flowObj = null;
738 try {
739 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
740 != null) {
741 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
742 flowPath.flowId().toString());
743 } else {
744 flowObj = conn.utils().newFlowPath(conn);
745 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
746 flowPath.flowId().toString());
747 }
748 } catch (Exception e) {
749 // TODO: handle exceptions
750 conn.endTx(Transaction.ROLLBACK);
751 log.error(":addFlow FlowId:{} failed",
752 flowPath.flowId().toString());
753 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700754 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000755 log.error(":addFlow FlowId:{} failed: Flow object not created",
756 flowPath.flowId().toString());
757 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800758 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700759 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800760
761 //
762 // Set the Flow key:
763 // - flowId
764 //
765 flowObj.setFlowId(flowPath.flowId().toString());
766 flowObj.setType("flow");
767
768 //
769 // Set the Flow attributes:
770 // - flowPath.installerId()
771 // - flowPath.dataPath().srcPort()
772 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700773 // - flowPath.matchEthernetFrameType()
774 // - flowPath.matchSrcIPv4Net()
775 // - flowPath.matchDstIPv4Net()
776 // - flowPath.matchSrcMac()
777 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800778 //
779 flowObj.setInstallerId(flowPath.installerId().toString());
780 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
781 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
782 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
783 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700784 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
785 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
786 }
787 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
788 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
789 }
790 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
791 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
792 }
793 if (flowPath.flowEntryMatch().matchSrcMac()) {
794 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
795 }
796 if (flowPath.flowEntryMatch().matchDstMac()) {
797 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
798 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800799
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700800 if (dataPathSummaryStr != null) {
801 flowObj.setDataPathSummary(dataPathSummaryStr);
802 } else {
803 flowObj.setDataPathSummary("");
804 }
805
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800806 // Flow edges:
807 // HeadFE
808
809
810 //
811 // Flow Entries:
812 // flowPath.dataPath().flowEntries()
813 //
814 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
815 IFlowEntry flowEntryObj = null;
816 boolean found = false;
817 try {
818 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
819 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
820 flowEntry.flowEntryId().toString());
821 found = true;
822 } else {
823 flowEntryObj = conn.utils().newFlowEntry(conn);
824 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
825 flowEntry.flowEntryId().toString());
826 }
827 } catch (Exception e) {
828 // TODO: handle exceptions
829 conn.endTx(Transaction.ROLLBACK);
830 log.error(":addFlow FlowEntryId:{} failed",
831 flowEntry.flowEntryId().toString());
832 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700833 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000834 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
835 flowEntry.flowEntryId().toString());
836 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800837 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700838 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800839
840 //
841 // Set the Flow Entry key:
842 // - flowEntry.flowEntryId()
843 //
844 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
845 flowEntryObj.setType("flow_entry");
846
847 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700848 // Set the Flow Entry Edges and attributes:
849 // - Switch edge
850 // - InPort edge
851 // - OutPort edge
852 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800853 // - flowEntry.flowEntryMatch()
854 // - flowEntry.flowEntryActions()
855 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800856 // - flowEntry.flowEntryUserState()
857 // - flowEntry.flowEntrySwitchState()
858 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700859 // - flowEntry.matchInPort()
860 // - flowEntry.matchEthernetFrameType()
861 // - flowEntry.matchSrcIPv4Net()
862 // - flowEntry.matchDstIPv4Net()
863 // - flowEntry.matchSrcMac()
864 // - flowEntry.matchDstMac()
865 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800866 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700867 ISwitchObject sw =
868 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800869 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700870 flowEntryObj.setSwitch(sw);
871 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700872 IPortObject inport =
873 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
874 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700875 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
876 flowEntryObj.setInPort(inport);
877 }
878 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
879 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
880 }
881 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
882 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
883 }
884 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
885 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
886 }
887 if (flowEntry.flowEntryMatch().matchSrcMac()) {
888 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
889 }
890 if (flowEntry.flowEntryMatch().matchDstMac()) {
891 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
892 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700893
894 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700895 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700896 IPortObject outport =
897 conn.utils().searchPort(conn,
898 flowEntry.dpid().toString(),
899 fa.actionOutput().port().value());
900 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
901 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700902 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700903 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800904 // TODO: Hacks with hard-coded state names!
905 if (found)
906 flowEntryObj.setUserState("FE_USER_MODIFY");
907 else
908 flowEntryObj.setUserState("FE_USER_ADD");
909 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
910 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700911 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800912 //
913
914 // Flow Entries edges:
915 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700916 // NextFE (TODO)
917 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800918 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700919 flowEntryObj.setFlow(flowObj);
920 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800921 }
922 conn.endTx(Transaction.COMMIT);
923
924 //
925 // TODO: We need a proper Flow ID allocation mechanism.
926 //
927 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700928
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800929 return true;
930 }
931
932 /**
933 * Delete a previously added flow.
934 *
935 * @param flowId the Flow ID of the flow to delete.
936 * @return true on success, otherwise false.
937 */
938 @Override
939 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700940 if (flowId.value() == measurementFlowId) {
941 modifiedMeasurementFlowTime = System.nanoTime();
942 }
943
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800944 IFlowPath flowObj = null;
945 //
946 // We just mark the entries for deletion,
947 // and let the switches remove each individual entry after
948 // it has been removed from the switches.
949 //
950 try {
951 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
952 != null) {
953 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
954 flowId.toString());
955 } else {
956 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
957 flowId.toString());
958 }
959 } catch (Exception e) {
960 // TODO: handle exceptions
961 conn.endTx(Transaction.ROLLBACK);
962 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
963 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700964 if (flowObj == null) {
965 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800966 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700967 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800968
969 //
970 // Find and mark for deletion all Flow Entries
971 //
972 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
973 boolean empty = true; // TODO: an ugly hack
974 for (IFlowEntry flowEntryObj : flowEntries) {
975 empty = false;
976 // flowObj.removeFlowEntry(flowEntryObj);
977 // conn.utils().removeFlowEntry(conn, flowEntryObj);
978 flowEntryObj.setUserState("FE_USER_DELETE");
979 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
980 }
981 // Remove from the database empty flows
982 if (empty)
983 conn.utils().removeFlowPath(conn, flowObj);
984 conn.endTx(Transaction.COMMIT);
985
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800986 return true;
987 }
988
989 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700990 * Clear the state for a previously added flow.
991 *
992 * @param flowId the Flow ID of the flow to clear.
993 * @return true on success, otherwise false.
994 */
995 @Override
996 public boolean clearFlow(FlowId flowId) {
997 IFlowPath flowObj = null;
998 try {
999 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1000 != null) {
1001 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1002 flowId.toString());
1003 } else {
1004 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1005 flowId.toString());
1006 }
1007 } catch (Exception e) {
1008 // TODO: handle exceptions
1009 conn.endTx(Transaction.ROLLBACK);
1010 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1011 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001012 if (flowObj == null) {
1013 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001014 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001015 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001016
1017 //
1018 // Remove all Flow Entries
1019 //
1020 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1021 for (IFlowEntry flowEntryObj : flowEntries) {
1022 flowObj.removeFlowEntry(flowEntryObj);
1023 conn.utils().removeFlowEntry(conn, flowEntryObj);
1024 }
1025 // Remove the Flow itself
1026 conn.utils().removeFlowPath(conn, flowObj);
1027 conn.endTx(Transaction.COMMIT);
1028
1029 return true;
1030 }
1031
1032 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001033 * Get a previously added flow.
1034 *
1035 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001036 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001037 */
1038 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001039 public FlowPath getFlow(FlowId flowId) {
1040 IFlowPath flowObj = null;
1041 try {
1042 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
1043 != null) {
1044 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1045 flowId.toString());
1046 } else {
1047 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1048 flowId.toString());
1049 }
1050 } catch (Exception e) {
1051 // TODO: handle exceptions
1052 conn.endTx(Transaction.ROLLBACK);
1053 log.error(":getFlow FlowId:{} failed", flowId.toString());
1054 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001055 if (flowObj == null) {
1056 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001057 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001058 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001059
1060 //
1061 // Extract the Flow state
1062 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001063 FlowPath flowPath = extractFlowPath(flowObj);
1064 conn.endTx(Transaction.COMMIT);
1065
1066 return flowPath;
1067 }
1068
1069 /**
1070 * Get all previously added flows by a specific installer for a given
1071 * data path endpoints.
1072 *
1073 * @param installerId the Caller ID of the installer of the flow to get.
1074 * @param dataPathEndpoints the data path endpoints of the flow to get.
1075 * @return the Flow Paths if found, otherwise null.
1076 */
1077 @Override
1078 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1079 DataPathEndpoints dataPathEndpoints) {
1080 //
1081 // TODO: The implementation below is not optimal:
1082 // We fetch all flows, and then return only the subset that match
1083 // the query conditions.
1084 // We should use the appropriate Titan/Gremlin query to filter-out
1085 // the flows as appropriate.
1086 //
1087 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001088 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001089
1090 if (allFlows == null) {
1091 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001092 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001093 }
1094
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001095 for (FlowPath flow : allFlows) {
1096 //
1097 // TODO: String-based comparison is sub-optimal.
1098 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001099 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001100 //
1101 if (! flow.installerId().toString().equals(installerId.toString()))
1102 continue;
1103 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1104 continue;
1105 }
1106 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1107 continue;
1108 }
1109 flowPaths.add(flow);
1110 }
1111
1112 if (flowPaths.isEmpty()) {
1113 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001114 } else {
1115 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1116 }
1117
1118 return flowPaths;
1119 }
1120
1121 /**
1122 * Get all installed flows by all installers for given data path endpoints.
1123 *
1124 * @param dataPathEndpoints the data path endpoints of the flows to get.
1125 * @return the Flow Paths if found, otherwise null.
1126 */
1127 @Override
1128 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1129 //
1130 // TODO: The implementation below is not optimal:
1131 // We fetch all flows, and then return only the subset that match
1132 // the query conditions.
1133 // We should use the appropriate Titan/Gremlin query to filter-out
1134 // the flows as appropriate.
1135 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001136 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1137 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001138
1139 if (allFlows == null) {
1140 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001141 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001142 }
1143
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001144 for (FlowPath flow : allFlows) {
1145 //
1146 // TODO: String-based comparison is sub-optimal.
1147 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001148 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001149 //
1150 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1151 continue;
1152 }
1153 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1154 continue;
1155 }
1156 flowPaths.add(flow);
1157 }
1158
1159 if (flowPaths.isEmpty()) {
1160 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001161 } else {
1162 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1163 }
1164
1165 return flowPaths;
1166 }
1167
1168 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001169 * Get summary of all installed flows by all installers in a given range
1170 *
1171 * @param flowId the data path endpoints of the flows to get.
1172 * @param maxFlows: the maximum number of flows to be returned
1173 * @return the Flow Paths if found, otherwise null.
1174 */
1175 @Override
1176 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
1177 //
1178 // TODO: The implementation below is not optimal:
1179 // We fetch all flows, and then return only the subset that match
1180 // the query conditions.
1181 // We should use the appropriate Titan/Gremlin query to filter-out
1182 // the flows as appropriate.
1183 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001184 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1185
1186 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001187
1188 if (allFlows == null) {
1189 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001190 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001191 }
1192
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001193 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001194
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001195 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001196 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001197
1198 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -07001199 //if (flow.flowId().value() < flowId.value()) {
1200 // continue;
1201 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001202
1203 // Summarize by making null flow entry fields that are not relevant to report
1204 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1205 flowEntry.setFlowEntryActions(null);
1206 flowEntry.setFlowEntryMatch(null);
1207 }
1208
1209 flowPaths.add(flow);
1210 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1211 break;
1212 }
1213 }
1214
1215 if (flowPaths.isEmpty()) {
1216 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001217 } else {
1218 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1219 }
1220
1221 return flowPaths;
1222 }
1223
1224 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001225 * Get all installed flows by all installers.
1226 *
1227 * @return the Flow Paths if found, otherwise null.
1228 */
1229 @Override
1230 public ArrayList<FlowPath> getAllFlows() {
1231 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001232 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001233
1234 try {
1235 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1236 log.debug("Get all FlowPaths: found FlowPaths");
1237 } else {
1238 log.debug("Get all FlowPaths: no FlowPaths found");
1239 }
1240 } catch (Exception e) {
1241 // TODO: handle exceptions
1242 conn.endTx(Transaction.ROLLBACK);
1243 log.error(":getAllFlowPaths failed");
1244 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001245 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1246 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001247 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001248 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001249
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001250 for (IFlowPath flowObj : flowPathsObj) {
1251 //
1252 // Extract the Flow state
1253 //
1254 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001255 if (flowPath != null)
1256 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001257 }
1258
1259 conn.endTx(Transaction.COMMIT);
1260
1261 return flowPaths;
1262 }
1263
1264 /**
1265 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1266 *
1267 * @param flowObj the object to extract the Flow Path State from.
1268 * @return the extracted Flow Path State.
1269 */
1270 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001271 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001272
1273 //
1274 // Extract the Flow state
1275 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001276 String flowIdStr = flowObj.getFlowId();
1277 String installerIdStr = flowObj.getInstallerId();
1278 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001279 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001280 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001281 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001282
1283 if ((flowIdStr == null) ||
1284 (installerIdStr == null) ||
1285 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001286 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001287 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001288 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001289 // TODO: A work-around, becauuse of some bogus database objects
1290 return null;
1291 }
1292
1293 flowPath.setFlowId(new FlowId(flowIdStr));
1294 flowPath.setInstallerId(new CallerId(installerIdStr));
1295 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001296 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001297 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001298 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001299 //
1300 // Extract the match conditions common for all Flow Entries
1301 //
1302 {
1303 FlowEntryMatch match = new FlowEntryMatch();
1304 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1305 if (matchEthernetFrameType != null)
1306 match.enableEthernetFrameType(matchEthernetFrameType);
1307 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1308 if (matchSrcIPv4Net != null)
1309 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1310 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1311 if (matchDstIPv4Net != null)
1312 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1313 String matchSrcMac = flowObj.getMatchSrcMac();
1314 if (matchSrcMac != null)
1315 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1316 String matchDstMac = flowObj.getMatchDstMac();
1317 if (matchDstMac != null)
1318 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1319 flowPath.setFlowEntryMatch(match);
1320 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001321
1322 //
1323 // Extract all Flow Entries
1324 //
1325 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1326 for (IFlowEntry flowEntryObj : flowEntries) {
1327 FlowEntry flowEntry = new FlowEntry();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001328 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1329 String switchDpidStr = flowEntryObj.getSwitchDpid();
1330 String userState = flowEntryObj.getUserState();
1331 String switchState = flowEntryObj.getSwitchState();
1332
1333 if ((flowEntryIdStr == null) ||
1334 (switchDpidStr == null) ||
1335 (userState == null) ||
1336 (switchState == null)) {
1337 // TODO: A work-around, becauuse of some bogus database objects
1338 continue;
1339 }
1340 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1341 flowEntry.setDpid(new Dpid(switchDpidStr));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -07001342
1343 //
1344 // Extract the match conditions
1345 //
1346 FlowEntryMatch match = new FlowEntryMatch();
1347 Short matchInPort = flowEntryObj.getMatchInPort();
1348 if (matchInPort != null)
1349 match.enableInPort(new Port(matchInPort));
1350 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1351 if (matchEthernetFrameType != null)
1352 match.enableEthernetFrameType(matchEthernetFrameType);
1353 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1354 if (matchSrcIPv4Net != null)
1355 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1356 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1357 if (matchDstIPv4Net != null)
1358 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1359 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1360 if (matchSrcMac != null)
1361 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1362 String matchDstMac = flowEntryObj.getMatchDstMac();
1363 if (matchDstMac != null)
1364 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1365 flowEntry.setFlowEntryMatch(match);
1366
1367 //
1368 // Extract the actions
1369 //
1370 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1371 Short actionOutputPort = flowEntryObj.getActionOutput();
1372 if (actionOutputPort != null) {
1373 FlowEntryAction action = new FlowEntryAction();
1374 action.setActionOutput(new Port(actionOutputPort));
1375 actions.add(action);
1376 }
1377 flowEntry.setFlowEntryActions(actions);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001378 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001379 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1380 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -08001381 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001382 // and FlowEntryErrorState.
1383 //
1384 flowPath.dataPath().flowEntries().add(flowEntry);
1385 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001386
1387 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001388 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001389
1390 /**
1391 * Add and maintain a shortest-path flow.
1392 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001393 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001394 *
1395 * @param flowPath the Flow Path with the endpoints and the match
1396 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001397 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001398 */
1399 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001400 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001401 String dataPathSummaryStr = null;
1402
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001403 //
1404 // Do the shortest path computation
1405 //
1406 DataPath dataPath =
1407 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1408 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001409 if (dataPath == null) {
1410 // We need the DataPath to populate the Network MAP
1411 dataPath = new DataPath();
1412 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1413 dataPath.setDstPort(flowPath.dataPath().dstPort());
1414 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001415
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001416 // Compute the Data Path summary
1417 dataPathSummaryStr = dataPath.dataPathSummary();
1418
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001419 //
1420 // Set the incoming port matching and the outgoing port output
1421 // actions for each flow entry.
1422 //
1423 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1424 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001425 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001426 flowEntry.setFlowEntryMatch(flowEntryMatch);
1427 flowEntryMatch.enableInPort(flowEntry.inPort());
1428
1429 // Set the outgoing port output action
1430 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1431 if (flowEntryActions == null) {
1432 flowEntryActions = new ArrayList<FlowEntryAction>();
1433 flowEntry.setFlowEntryActions(flowEntryActions);
1434 }
1435 FlowEntryAction flowEntryAction = new FlowEntryAction();
1436 flowEntryAction.setActionOutput(flowEntry.outPort());
1437 flowEntryActions.add(flowEntryAction);
1438 }
1439
1440 //
1441 // Prepare the computed Flow Path
1442 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001443 FlowPath computedFlowPath = new FlowPath();
1444 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1445 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1446 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001447 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001448
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001449 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001450 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001451 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001452
1453 // TODO: Mark the flow for maintenance purpose
1454
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001455 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001456 }
1457
1458 /**
1459 * Create a Flow from port to port.
1460 *
1461 * TODO: We don't need it for now.
1462 *
1463 * @param src_port the source port.
1464 * @param dest_port the destination port.
1465 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001466 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001467 public void createFlow(IPortObject src_port, IPortObject dest_port) {
1468 // TODO: We don't need it for now.
1469 }
1470
1471 /**
1472 * Get all Flows matching a source and a destination port.
1473 *
1474 * TODO: Pankaj might be implementing it later.
1475 *
1476 * @param src_port the source port to match.
1477 * @param dest_port the destination port to match.
1478 * @return all flows matching the source and the destination port.
1479 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001480 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001481 public Iterable<FlowPath> getFlows(IPortObject src_port,
1482 IPortObject dest_port) {
1483 // TODO: Pankaj might be implementing it later.
1484 return null;
1485 }
1486
1487 /**
1488 * Get all Flows going out from a port.
1489 *
1490 * TODO: We need it now: Pankaj
1491 *
1492 * @param port the port to match.
1493 * @return the list of flows that are going out from the port.
1494 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001495 @Override
Pankaj Berde83d83382013-03-28 13:55:34 -07001496 public Iterable<FlowPath> getOutFlows(IPortObject port) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001497 // TODO: We need it now: Pankaj
1498 return null;
1499 }
1500
1501 /**
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001502 * Reconcile all flows on inactive switch port.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001503 *
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001504 * @param portObject the port that has become inactive.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001505 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001506 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001507 public void reconcileFlows(IPortObject portObject) {
1508 Iterable<IFlowEntry> inFlowEntries = portObject.getInFlowEntries();
1509 Iterable<IFlowEntry> outFlowEntries = portObject.getOutFlowEntries();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001510
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001511 //
1512 // Collect all affected Flow IDs from the affected flow entries
1513 //
1514 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
1515 for (IFlowEntry flowEntryObj: inFlowEntries) {
1516 IFlowPath flowObj = flowEntryObj.getFlow();
1517 if (flowObj != null)
1518 flowObjSet.add(flowObj);
1519 }
1520 for (IFlowEntry flowEntryObj: outFlowEntries) {
1521 IFlowPath flowObj = flowEntryObj.getFlow();
1522 if (flowObj != null)
1523 flowObjSet.add(flowObj);
1524 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001525
1526 // Reconcile the affected flows
1527 reconcileFlows(flowObjSet);
1528 }
1529
1530 /**
1531 * Reconcile all flows in a set.
1532 *
1533 * @param flowObjSet the set of flows that need to be reconciliated.
1534 */
1535 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1536 if (! flowObjSet.iterator().hasNext())
1537 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001538
1539 //
1540 // Remove the old Flow Entries, and add the new Flow Entries
1541 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001542
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001543 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001544 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001545 for (IFlowPath flowObj : flowObjSet) {
1546 FlowPath flowPath = extractFlowPath(flowObj);
1547 if (flowPath == null)
1548 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001549 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001550
1551 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001552 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001553 //
1554 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001555 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001556 for (IFlowEntry flowEntryObj : flowEntries) {
1557 String dpidStr = flowEntryObj.getSwitchDpid();
1558 if (dpidStr == null)
1559 continue;
1560 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001561 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001562 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1563 if (mySwitch == null)
1564 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001565 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001566 deleteFlowEntries.add(flowEntryObj);
1567 }
1568 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001569 flowObj.removeFlowEntry(flowEntryObj);
1570 conn.utils().removeFlowEntry(conn, flowEntryObj);
1571 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001572 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001573
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001574 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001575 //
1576 // Delete the flow entries from the switches
1577 //
1578 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1579 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001580 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1581 if (mySwitch == null) {
1582 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001583 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001584 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001585 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001586 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001587 }
1588
1589 //
1590 // Calculate the new shortest path and install it in the
1591 // Network MAP.
1592 //
1593 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1594 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001595 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001596 flowPath.dataPath().srcPort().toString(),
1597 flowPath.dataPath().dstPort().toString());
1598 continue;
1599 }
1600
1601 //
1602 // Add the flow entries to the switches
1603 //
1604 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1605 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001606 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1607 if (mySwitch == null) {
1608 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001609 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001610 continue;
1611 }
1612
1613 IFlowEntry flowEntryObj =
1614 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1615 if (flowEntryObj == null) {
1616 //
1617 // TODO: Remove the "new Object[] wrapper in the statement
1618 // below after the SLF4J logger is upgraded to
1619 // Version 1.7.5
1620 //
1621 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1622 new Object[] {
1623 flowEntry.dpid(),
1624 flowPath.dataPath().srcPort(),
1625 flowPath.dataPath().dstPort()
1626 });
1627 continue;
1628 }
1629 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001630 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001631 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1632 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001633 }
1634 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001635 }
1636
1637 /**
1638 * Reconcile all flows between a source and a destination port.
1639 *
1640 * TODO: We don't need it for now.
1641 *
1642 * @param src_port the source port.
1643 * @param dest_port the destination port.
1644 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001645 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001646 public void reconcileFlow(IPortObject src_port, IPortObject dest_port) {
1647 // TODO: We don't need it for now.
1648 }
1649
1650 /**
1651 * Compute the shortest path between a source and a destination ports.
1652 *
1653 * @param src_port the source port.
1654 * @param dest_port the destination port.
1655 * @return the computed shortest path between the source and the
1656 * destination ports. The flow entries in the path itself would
1657 * contain the incoming port matching and the outgoing port output
1658 * actions set. However, the path itself will NOT have the Flow ID,
1659 * Installer ID, and any additional matching conditions for the
1660 * flow entries (e.g., source or destination MAC address, etc).
1661 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001662 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001663 public FlowPath computeFlowPath(IPortObject src_port,
1664 IPortObject dest_port) {
1665 //
1666 // Prepare the arguments
1667 //
1668 String dpidStr = src_port.getSwitch().getDPID();
1669 Dpid srcDpid = new Dpid(dpidStr);
1670 Port srcPort = new Port(src_port.getNumber());
1671
1672 dpidStr = dest_port.getSwitch().getDPID();
1673 Dpid dstDpid = new Dpid(dpidStr);
1674 Port dstPort = new Port(dest_port.getNumber());
1675
1676 SwitchPort src = new SwitchPort(srcDpid, srcPort);
1677 SwitchPort dst = new SwitchPort(dstDpid, dstPort);
1678
1679 //
1680 // Do the shortest path computation
1681 //
1682 DataPath dataPath = topoRouteService.getShortestPath(src, dst);
1683 if (dataPath == null)
1684 return null;
1685
1686 //
1687 // Set the incoming port matching and the outgoing port output
1688 // actions for each flow entry.
1689 //
1690 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1691 // Set the incoming port matching
1692 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1693 if (flowEntryMatch == null) {
1694 flowEntryMatch = new FlowEntryMatch();
1695 flowEntry.setFlowEntryMatch(flowEntryMatch);
1696 }
1697 flowEntryMatch.enableInPort(flowEntry.inPort());
1698
1699 // Set the outgoing port output action
1700 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1701 if (flowEntryActions == null) {
1702 flowEntryActions = new ArrayList<FlowEntryAction>();
1703 flowEntry.setFlowEntryActions(flowEntryActions);
1704 }
1705 FlowEntryAction flowEntryAction = new FlowEntryAction();
1706 flowEntryAction.setActionOutput(flowEntry.outPort());
1707 flowEntryActions.add(flowEntryAction);
1708 }
1709
1710 //
1711 // Prepare the return result
1712 //
1713 FlowPath flowPath = new FlowPath();
1714 flowPath.setDataPath(dataPath);
1715
1716 return flowPath;
1717 }
1718
1719 /**
1720 * Get all Flow Entries of a Flow.
1721 *
1722 * @param flow the flow whose flow entries should be returned.
1723 * @return the flow entries of the flow.
1724 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001725 @Override
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001726 public Iterable<FlowEntry> getFlowEntries(FlowPath flow) {
1727 return flow.dataPath().flowEntries();
1728 }
1729
1730 /**
1731 * Install a Flow Entry on a switch.
1732 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001733 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001734 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001735 * @param flowEntry the flow entry to install.
1736 * @return true on success, otherwise false.
1737 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001738 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001739 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1740 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001741 //
1742 // Create the OpenFlow Flow Modification Entry to push
1743 //
1744 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1745 .getMessage(OFType.FLOW_MOD);
1746 long cookie = flowEntry.flowEntryId().value();
1747
1748 short flowModCommand = OFFlowMod.OFPFC_ADD;
1749 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1750 flowModCommand = OFFlowMod.OFPFC_ADD;
1751 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1752 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1753 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1754 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1755 } else {
1756 // Unknown user state. Ignore the entry
1757 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1758 flowEntry.flowEntryId().toString(),
1759 flowEntry.flowEntryUserState());
1760 return false;
1761 }
1762
1763 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001764 // Fetch the match conditions.
1765 //
1766 // NOTE: The Flow matching conditions common for all Flow Entries are
1767 // used ONLY if a Flow Entry does NOT have the corresponding matching
1768 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001769 //
1770 OFMatch match = new OFMatch();
1771 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001772 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1773 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1774
1775 // Match the Incoming Port
1776 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001777 if (matchInPort != null) {
1778 match.setInputPort(matchInPort.value());
1779 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1780 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001781
1782 // Match the Ethernet Frame Type
1783 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1784 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1785 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1786 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001787 if (matchEthernetFrameType != null) {
1788 match.setDataLayerType(matchEthernetFrameType);
1789 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1790 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001791
1792 // Match the Source IPv4 Network prefix
1793 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1794 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1795 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1796 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001797 if (matchSrcIPv4Net != null) {
1798 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1799 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001800
1801 // Natch the Destination IPv4 Network prefix
1802 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1803 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1804 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1805 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001806 if (matchDstIPv4Net != null) {
1807 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1808 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001809
1810 // Match the Source MAC address
1811 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1812 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1813 matchSrcMac = flowPathMatch.srcMac();
1814 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001815 if (matchSrcMac != null) {
1816 match.setDataLayerSource(matchSrcMac.toString());
1817 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1818 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001819
1820 // Match the Destination MAC address
1821 MACAddress matchDstMac = flowEntryMatch.dstMac();
1822 if ((matchDstMac == null) && (flowPathMatch != null)) {
1823 matchDstMac = flowPathMatch.dstMac();
1824 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001825 if (matchDstMac != null) {
1826 match.setDataLayerDestination(matchDstMac.toString());
1827 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1828 }
1829
1830 //
1831 // Fetch the actions
1832 //
1833 // TODO: For now we support only the "OUTPUT" actions.
1834 //
1835 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1836 List<OFAction> actions = new ArrayList<OFAction>();
1837 ArrayList<FlowEntryAction> flowEntryActions =
1838 flowEntry.flowEntryActions();
1839 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1840 FlowEntryAction.ActionOutput actionOutput =
1841 flowEntryAction.actionOutput();
1842 if (actionOutput != null) {
1843 short actionOutputPort = actionOutput.port().value();
1844 OFActionOutput action = new OFActionOutput();
1845 // XXX: The max length is hard-coded for now
1846 action.setMaxLength((short)0xffff);
1847 action.setPort(actionOutputPort);
1848 actions.add(action);
1849 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1850 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1851 fm.setOutPort(actionOutputPort);
1852 }
1853 }
1854 }
1855
1856 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1857 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1858 .setPriority(PRIORITY_DEFAULT)
1859 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1860 .setCookie(cookie)
1861 .setCommand(flowModCommand)
1862 .setMatch(match)
1863 .setActions(actions)
1864 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1865
1866 //
1867 // TODO: Set the following flag
1868 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1869 // See method ForwardingBase::pushRoute()
1870 //
1871
1872 //
1873 // Write the message to the switch
1874 //
1875 try {
1876 messageDamper.write(mySwitch, fm, null);
1877 mySwitch.flush();
1878 } catch (IOException e) {
1879 log.error("Failure writing flow mod from network map", e);
1880 return false;
1881 }
1882 return true;
1883 }
1884
1885 /**
1886 * Remove a Flow Entry from a switch.
1887 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001888 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001889 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001890 * @param flowEntry the flow entry to remove.
1891 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001892 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001893 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001894 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1895 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001896 //
1897 // The installFlowEntry() method implements both installation
1898 // and removal of flow entries.
1899 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001900 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001901 }
1902
1903 /**
1904 * Install a Flow Entry on a remote controller.
1905 *
1906 * TODO: We need it now: Jono
1907 * - For now it will make a REST call to the remote controller.
1908 * - Internally, it needs to know the name of the remote controller.
1909 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001910 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001911 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001912 * @return true on success, otherwise false.
1913 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001914 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001915 public boolean installRemoteFlowEntry(FlowPath flowPath,
1916 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001917 // TODO: We need it now: Jono
1918 // - For now it will make a REST call to the remote controller.
1919 // - Internally, it needs to know the name of the remote controller.
1920 return true;
1921 }
1922
1923 /**
1924 * Remove a flow entry on a remote controller.
1925 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001926 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001927 * @param flowEntry the flow entry to remove.
1928 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001929 */
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001930 @Override
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001931 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1932 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001933 //
1934 // The installRemoteFlowEntry() method implements both installation
1935 // and removal of flow entries.
1936 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001937 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001938 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001939}