blob: cd6f5eb6c4367da291ea5c1f275d19a6105e6f17 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00004import java.io.PrintWriter;
5import java.io.StringWriter;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.ArrayList;
7import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07008import java.util.Collections;
9import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000012import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000015import java.util.Random;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +000016import java.util.concurrent.ConcurrentLinkedQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.Executors;
18import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070028import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.util.OFMessageDamper;
yoshi2fd4c7e2013-11-22 15:47:55 -080030import net.onrc.onos.graph.DBOperation;
31import net.onrc.onos.graph.GraphDBManager;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070032import net.onrc.onos.ofcontroller.core.INetMapStorage;
33import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
36import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
37import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070038import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070039import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070040import net.onrc.onos.ofcontroller.util.CallerId;
41import net.onrc.onos.ofcontroller.util.DataPath;
42import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
43import net.onrc.onos.ofcontroller.util.Dpid;
44import net.onrc.onos.ofcontroller.util.FlowEntry;
45import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070046import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
47import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.FlowEntryId;
49import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
50import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
51import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
52import net.onrc.onos.ofcontroller.util.FlowId;
53import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070054import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070055import net.onrc.onos.ofcontroller.util.IPv4Net;
56import net.onrc.onos.ofcontroller.util.Port;
57import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080058
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;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070064import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
admin944ef4f2013-10-08 17:48:37 -070068/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070069 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070070 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070071public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072
yoshi2fd4c7e2013-11-22 15:47:55 -080073 protected DBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080074
75 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070076 protected volatile IFloodlightProviderService floodlightProvider;
77 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070078 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080079
80 protected OFMessageDamper messageDamper;
81
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070082 //
83 // TODO: Values copied from elsewhere (class LearningSwitch).
84 // The local copy should go away!
85 //
86 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
87 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
88 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
89 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
90 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080091
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000092 // Flow Entry ID generation state
93 private static Random randomGenerator = new Random();
94 private static int nextFlowEntryIdPrefix = 0;
95 private static int nextFlowEntryIdSuffix = 0;
96 private static long nextFlowEntryId = 0;
97
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070098 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private static long measurementFlowId = 100000;
100 private static String measurementFlowIdStr = "0x186a0"; // 100000
101 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700102 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700103
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800104 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800105 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
106
107 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700108 private ScheduledExecutorService mapReaderScheduler;
109 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700110
admin944ef4f2013-10-08 17:48:37 -0700111 /**
112 * Periodic task for reading the Flow Entries and pushing changes
113 * into the switches.
114 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700115 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800116 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700117 try {
118 runImpl();
119 } catch (Exception e) {
120 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700121 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700122 return;
123 }
124 }
125
126 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700127 long startTime = System.nanoTime();
128 int counterAllFlowEntries = 0;
129 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700130
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800131 if (floodlightProvider == null) {
132 log.debug("FloodlightProvider service not found!");
133 return;
134 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000135 Map<Long, IOFSwitch> mySwitches =
136 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700137 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700138 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700139 return;
140 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700141 LinkedList<IFlowEntry> addFlowEntries =
142 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143 LinkedList<IFlowEntry> deleteFlowEntries =
144 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700145
146 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700147 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700148 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700149 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700150 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000151 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700152 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700153 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700154 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000155
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000156 String dpidStr = flowEntryObj.getSwitchDpid();
157 if (dpidStr == null)
158 continue;
159 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800160 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000161 if (mySwitch == null)
162 continue; // Ignore the entry: not my switch
163
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700164 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700165 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 if (flowObj == null)
167 continue; // Should NOT happen
168 if (flowObj.getFlowId() == null)
169 continue; // Invalid entry
170
171 //
172 // NOTE: For now we process the DELETE before the ADD
173 // to cover the more common scenario.
174 // TODO: This is error prone and needs to be fixed!
175 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000176 String userState = flowEntryObj.getUserState();
177 if (userState == null)
178 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700179 if (userState.equals("FE_USER_DELETE")) {
180 // An entry that needs to be deleted.
181 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700182 installFlowEntry(mySwitch, flowObj, flowEntryObj);
183 } else {
184 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700185 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700186 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700187 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700188 // TODO: Commented-out for now
189 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700190 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700191 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700192 processed_measurement_flow = true;
193 }
194 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700195 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700196 }
197
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700198 //
199 // Process the Flow Entries that need to be added
200 //
201 for (IFlowEntry flowEntryObj : addFlowEntries) {
202 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700203 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700204 if (flowObj == null)
205 continue; // Should NOT happen
206 if (flowObj.getFlowId() == null)
207 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700208
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700209 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700210 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 if (mySwitch == null)
212 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700213 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800214 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000215
216 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000217 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700218 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219 //
220 // TODO: We should use the OpenFlow Barrier mechanism
221 // to check for errors, and delete the Flow Entries after the
222 // Barrier message is received.
223 //
224 while (! deleteFlowEntries.isEmpty()) {
225 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
226 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700227 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000228 if (flowObj == null) {
229 log.debug("Did not find FlowPath to be deleted");
230 continue;
231 }
232 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700233 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000234 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700235
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700236 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700237
238 if (processed_measurement_flow) {
239 long estimatedTime =
240 System.nanoTime() - modifiedMeasurementFlowTime;
241 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
242 (double)estimatedTime / 1000000000 + " sec";
243 log.debug(logMsg);
244 }
245
246 long estimatedTime = System.nanoTime() - startTime;
247 double rate = 0.0;
248 if (estimatedTime > 0)
249 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
250 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
251 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
252 counterMyNotUpdatedFlowEntries + " in " +
253 (double)estimatedTime / 1000000000 + " sec: " +
254 rate + " paths/s";
255 log.debug(logMsg);
256 }
257 };
258
admin944ef4f2013-10-08 17:48:37 -0700259 /**
260 * Periodic task for reading the Flow Paths and recomputing the
261 * shortest paths.
262 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700263 final Runnable shortestPathReconcile = new Runnable() {
264 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700265 try {
266 runImpl();
267 } catch (Exception e) {
268 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700269 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700270 return;
271 }
272 }
273
274 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700275 long startTime = System.nanoTime();
276 int counterAllFlowPaths = 0;
277 int counterMyFlowPaths = 0;
278
279 if (floodlightProvider == null) {
280 log.debug("FloodlightProvider service not found!");
281 return;
282 }
283 Map<Long, IOFSwitch> mySwitches =
284 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700285 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700286 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700287 return;
288 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700289 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
290
291 boolean processed_measurement_flow = false;
292
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700293 //
294 // Fetch and recompute the Shortest Path for those
295 // Flow Paths this controller is responsible for.
296 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000297 Map<Long, ?> shortestPathTopo =
298 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700299 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700300 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700301 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700302 if (flowPathObj == null)
303 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700304
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700305 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000306 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700308 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700309 //
310 // Use the source DPID as a heuristic to decide
311 // which controller is responsible for maintaining the
312 // shortest path.
313 // NOTE: This heuristic is error-prone: if the switch
314 // goes away and no controller is responsible for that
315 // switch, then the original Flow Path is not cleaned-up
316 //
317 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
318 if (mySwitch == null)
319 continue; // Ignore: not my responsibility
320
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700321 // Test the Data Path Summary string
322 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
323 if (dataPathSummaryStr == null)
324 continue; // Could be invalid entry?
325 if (dataPathSummaryStr.isEmpty())
326 continue; // No need to maintain this flow
327
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000328 //
329 // Test whether we need to complete the Flow cleanup,
330 // if the Flow has been deleted by the user.
331 //
332 String flowUserState = flowPathObj.getUserState();
333 if ((flowUserState != null)
334 && flowUserState.equals("FE_USER_DELETE")) {
335 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
336 boolean empty = true; // TODO: an ugly hack
337 for (IFlowEntry flowEntryObj : flowEntries) {
338 empty = false;
339 break;
340 }
341 if (empty)
342 deleteFlows.add(flowPathObj);
343 }
344
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000345 // Fetch the fields needed to recompute the shortest path
346 Short srcPortShort = flowPathObj.getSrcPort();
347 String dstDpidStr = flowPathObj.getDstSwitch();
348 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700349 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000350 if ((srcPortShort == null) ||
351 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700352 (dstPortShort == null) ||
353 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000354 continue;
355 }
356
357 Port srcPort = new Port(srcPortShort);
358 Dpid dstDpid = new Dpid(dstDpidStr);
359 Port dstPort = new Port(dstPortShort);
360 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
361 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700362 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000363
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700364 counterMyFlowPaths++;
365
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700366 //
367 // NOTE: Using here the regular getShortestPath() method
368 // won't work here, because that method calls internally
369 // "conn.endTx(Transaction.COMMIT)", and that will
370 // invalidate all handlers to the Titan database.
371 // If we want to experiment with calling here
372 // getShortestPath(), we need to refactor that code
373 // to avoid closing the transaction.
374 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700375 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000376 topoRouteService.getTopoShortestPath(shortestPathTopo,
377 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700378 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000379 if (dataPath == null) {
380 // We need the DataPath to compare the paths
381 dataPath = new DataPath();
382 dataPath.setSrcPort(srcSwitchPort);
383 dataPath.setDstPort(dstSwitchPort);
384 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700385 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000386
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700387 String newDataPathSummaryStr = dataPath.dataPathSummary();
388 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
389 continue; // Nothing changed
390
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700391 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700392 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000393
394 //
395 // Delete all leftover Flows marked for deletion from the
396 // Network MAP.
397 //
398 while (! deleteFlows.isEmpty()) {
399 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700400 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000401 }
402
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000403 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700404
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700405 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700406
407 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700408 long estimatedTime =
409 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700410 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
411 (double)estimatedTime / 1000000000 + " sec";
412 log.debug(logMsg);
413 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700414
415 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700416 double rate = 0.0;
417 if (estimatedTime > 0)
418 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700419 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700420 counterAllFlowPaths + " MyFlowPaths: " +
421 counterMyFlowPaths + " in " +
422 (double)estimatedTime / 1000000000 + " sec: " +
423 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700424 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425 }
426 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700427
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428
admin944ef4f2013-10-08 17:48:37 -0700429 /**
430 * Initialize the Flow Manager.
431 *
432 * @param conf the Graph Database configuration string.
433 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800434 @Override
yoshi2fd4c7e2013-11-22 15:47:55 -0800435 public void init(final String dbStore, final String conf) {
436 op = GraphDBManager.getDBOperation(dbStore, conf);
437 topoRouteService = new TopoRouteService(dbStore, conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800438 }
439
admin944ef4f2013-10-08 17:48:37 -0700440 /**
441 * Shutdown the Flow Manager operation.
442 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800443 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700444 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800445 }
446
admin944ef4f2013-10-08 17:48:37 -0700447 /**
448 * Shutdown the Flow Manager operation.
449 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800450 @Override
451 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700452 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800453 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800454
admin944ef4f2013-10-08 17:48:37 -0700455 /**
456 * Get the collection of offered module services.
457 *
458 * @return the collection of offered module services.
459 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800460 @Override
461 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
462 Collection<Class<? extends IFloodlightService>> l =
463 new ArrayList<Class<? extends IFloodlightService>>();
464 l.add(IFlowService.class);
465 return l;
466 }
467
admin944ef4f2013-10-08 17:48:37 -0700468 /**
469 * Get the collection of implemented services.
470 *
471 * @return the collection of implemented services.
472 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800473 @Override
474 public Map<Class<? extends IFloodlightService>, IFloodlightService>
475 getServiceImpls() {
476 Map<Class<? extends IFloodlightService>,
477 IFloodlightService> m =
478 new HashMap<Class<? extends IFloodlightService>,
479 IFloodlightService>();
480 m.put(IFlowService.class, this);
481 return m;
482 }
483
admin944ef4f2013-10-08 17:48:37 -0700484 /**
485 * Get the collection of modules this module depends on.
486 *
487 * @return the collection of modules this module depends on.
488 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800489 @Override
490 public Collection<Class<? extends IFloodlightService>>
491 getModuleDependencies() {
492 Collection<Class<? extends IFloodlightService>> l =
493 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800494 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800495 l.add(IRestApiService.class);
496 return l;
497 }
498
admin944ef4f2013-10-08 17:48:37 -0700499 /**
500 * Initialize the module.
501 *
502 * @param context the module context to use for the initialization.
503 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800504 @Override
505 public void init(FloodlightModuleContext context)
506 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700507 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800508 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800509 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800510 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
511 EnumSet.of(OFType.FLOW_MOD),
512 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700513
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800514 // TODO: An ugly hack!
515 String conf = "/tmp/cassandra.titan";
yoshi2fd4c7e2013-11-22 15:47:55 -0800516 this.init("titan", conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700517
admin944ef4f2013-10-08 17:48:37 -0700518 mapReaderScheduler = Executors.newScheduledThreadPool(1);
519 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800520 }
521
admin944ef4f2013-10-08 17:48:37 -0700522 /**
523 * Get the next Flow Entry ID to use.
524 *
525 * @return the next Flow Entry ID to use.
526 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700527 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000528 //
529 // Generate the next Flow Entry ID.
530 // NOTE: For now, the higher 32 bits are random, and
531 // the lower 32 bits are sequential.
532 // In the future, we need a better allocation mechanism.
533 //
534 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
535 nextFlowEntryIdPrefix = randomGenerator.nextInt();
536 nextFlowEntryIdSuffix = 0;
537 } else {
538 nextFlowEntryIdSuffix++;
539 }
540 long result = (long)nextFlowEntryIdPrefix << 32;
541 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
542 return result;
543 }
544
admin944ef4f2013-10-08 17:48:37 -0700545 /**
546 * Startup module operation.
547 *
548 * @param context the module context to use for the startup.
549 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800550 @Override
551 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700552 restApi.addRestletRoutable(new FlowWebRoutable());
Jonathan Hart50a94982013-04-10 14:49:51 -0700553
admin944ef4f2013-10-08 17:48:37 -0700554 // Initialize the Flow Entry ID generator
555 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Jonathan Hart50a94982013-04-10 14:49:51 -0700556
admin944ef4f2013-10-08 17:48:37 -0700557 mapReaderScheduler.scheduleAtFixedRate(
558 mapReader, 3, 3, TimeUnit.SECONDS);
559 shortestPathReconcileScheduler.scheduleAtFixedRate(
560 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800561 }
562
563 /**
564 * Add a flow.
565 *
566 * Internally, ONOS will automatically register the installer for
567 * receiving Flow Path Notifications for that path.
568 *
569 * @param flowPath the Flow Path to install.
570 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700571 * @param dataPathSummaryStr the data path summary string if the added
572 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800573 * @return true on success, otherwise false.
574 */
575 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700576 public boolean addFlow(FlowPath flowPath, FlowId flowId,
577 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700578 /*
579 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700580 if (flowPath.flowId().value() == measurementFlowId) {
581 modifiedMeasurementFlowTime = System.nanoTime();
582 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700583 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584
585 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000586 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800587 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700588 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800589 != null) {
590 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
591 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000592 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800593 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700594 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800595 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
596 flowPath.flowId().toString());
597 }
598 } catch (Exception e) {
599 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700600 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000601
602 StringWriter sw = new StringWriter();
603 e.printStackTrace(new PrintWriter(sw));
604 String stacktrace = sw.toString();
605
606 log.error(":addFlow FlowId:{} failed: {}",
607 flowPath.flowId().toString(),
608 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800609 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700610 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000611 log.error(":addFlow FlowId:{} failed: Flow object not created",
612 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700613 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800614 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700615 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800616
617 //
618 // Set the Flow key:
619 // - flowId
620 //
621 flowObj.setFlowId(flowPath.flowId().toString());
622 flowObj.setType("flow");
623
624 //
625 // Set the Flow attributes:
626 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700627 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800628 // - flowPath.dataPath().srcPort()
629 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700630 // - flowPath.matchSrcMac()
631 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700632 // - flowPath.matchEthernetFrameType()
633 // - flowPath.matchVlanId()
634 // - flowPath.matchVlanPriority()
635 // - flowPath.matchSrcIPv4Net()
636 // - flowPath.matchDstIPv4Net()
637 // - flowPath.matchIpProto()
638 // - flowPath.matchIpToS()
639 // - flowPath.matchSrcTcpUdpPort()
640 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700641 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642 //
643 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700644 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800645 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
646 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
647 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
648 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700649 if (flowPath.flowEntryMatch().matchSrcMac()) {
650 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
651 }
652 if (flowPath.flowEntryMatch().matchDstMac()) {
653 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
654 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700655 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
656 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
657 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700658 if (flowPath.flowEntryMatch().matchVlanId()) {
659 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
660 }
661 if (flowPath.flowEntryMatch().matchVlanPriority()) {
662 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
663 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700664 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
665 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
666 }
667 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
668 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
669 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700670 if (flowPath.flowEntryMatch().matchIpProto()) {
671 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700672 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700673 if (flowPath.flowEntryMatch().matchIpToS()) {
674 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
675 }
676 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
677 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
678 }
679 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
680 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700681 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700682 if (! flowPath.flowEntryActions().actions().isEmpty()) {
683 flowObj.setActions(flowPath.flowEntryActions().toString());
684 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800685
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700686 if (dataPathSummaryStr != null) {
687 flowObj.setDataPathSummary(dataPathSummaryStr);
688 } else {
689 flowObj.setDataPathSummary("");
690 }
691
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000692 if (found)
693 flowObj.setUserState("FE_USER_MODIFY");
694 else
695 flowObj.setUserState("FE_USER_ADD");
696
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800697 // Flow edges:
698 // HeadFE
699
700
701 //
702 // Flow Entries:
703 // flowPath.dataPath().flowEntries()
704 //
705 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700706 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700707 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800708 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700709 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800710 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700711 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800712
713 //
714 // TODO: We need a proper Flow ID allocation mechanism.
715 //
716 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700717
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800718 return true;
719 }
720
721 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700722 * Add a flow entry to the Network MAP.
723 *
724 * @param flowObj the corresponding Flow Path object for the Flow Entry.
725 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700726 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700727 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700728 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700729 // Flow edges
730 // HeadFE (TODO)
731
732 //
733 // Assign the FlowEntry ID.
734 //
735 if ((flowEntry.flowEntryId() == null) ||
736 (flowEntry.flowEntryId().value() == 0)) {
737 long id = getNextFlowEntryId();
738 flowEntry.setFlowEntryId(new FlowEntryId(id));
739 }
740
741 IFlowEntry flowEntryObj = null;
742 boolean found = false;
743 try {
744 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700745 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700746 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
747 flowEntry.flowEntryId().toString());
748 found = true;
749 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700750 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700751 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
752 flowEntry.flowEntryId().toString());
753 }
754 } catch (Exception e) {
755 log.error(":addFlow FlowEntryId:{} failed",
756 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700757 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700758 }
759 if (flowEntryObj == null) {
760 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
761 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700762 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700763 }
764
765 //
766 // Set the Flow Entry key:
767 // - flowEntry.flowEntryId()
768 //
769 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
770 flowEntryObj.setType("flow_entry");
771
772 //
773 // Set the Flow Entry Edges and attributes:
774 // - Switch edge
775 // - InPort edge
776 // - OutPort edge
777 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700778 // - flowEntry.dpid()
779 // - flowEntry.flowEntryUserState()
780 // - flowEntry.flowEntrySwitchState()
781 // - flowEntry.flowEntryErrorState()
782 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700783 // - flowEntry.matchSrcMac()
784 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700785 // - flowEntry.matchEthernetFrameType()
786 // - flowEntry.matchVlanId()
787 // - flowEntry.matchVlanPriority()
788 // - flowEntry.matchSrcIPv4Net()
789 // - flowEntry.matchDstIPv4Net()
790 // - flowEntry.matchIpProto()
791 // - flowEntry.matchIpToS()
792 // - flowEntry.matchSrcTcpUdpPort()
793 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700794 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700795 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700796 //
admin944ef4f2013-10-08 17:48:37 -0700797 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700798 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
799 flowEntryObj.setSwitch(sw);
800 if (flowEntry.flowEntryMatch().matchInPort()) {
801 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700802 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700803 flowEntry.flowEntryMatch().inPort().value());
804 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
805 flowEntryObj.setInPort(inport);
806 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700807 if (flowEntry.flowEntryMatch().matchSrcMac()) {
808 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
809 }
810 if (flowEntry.flowEntryMatch().matchDstMac()) {
811 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
812 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700813 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
814 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
815 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700816 if (flowEntry.flowEntryMatch().matchVlanId()) {
817 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
818 }
819 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
820 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
821 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700822 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
823 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
824 }
825 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
826 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
827 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700828 if (flowEntry.flowEntryMatch().matchIpProto()) {
829 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700830 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700831 if (flowEntry.flowEntryMatch().matchIpToS()) {
832 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
833 }
834 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
835 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
836 }
837 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
838 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700839 }
840
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700841 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700842 if (fa.actionOutput() != null) {
843 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700844 op.searchPort(flowEntry.dpid().toString(),
845 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700846 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700847 flowEntryObj.setOutPort(outport);
848 }
849 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700850 if (! flowEntry.flowEntryActions().isEmpty()) {
851 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
852 }
853
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700854 // TODO: Hacks with hard-coded state names!
855 if (found)
856 flowEntryObj.setUserState("FE_USER_MODIFY");
857 else
858 flowEntryObj.setUserState("FE_USER_ADD");
859 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
860 //
861 // TODO: Take care of the FlowEntryErrorState.
862 //
863
864 // Flow Entries edges:
865 // Flow
866 // NextFE (TODO)
867 if (! found) {
868 flowObj.addFlowEntry(flowEntryObj);
869 flowEntryObj.setFlow(flowObj);
870 }
871
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700872 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700873 }
874
875 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000876 * Delete all previously added flows.
877 *
878 * @return true on success, otherwise false.
879 */
880 @Override
881 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000882 List<Thread> threads = new LinkedList<Thread>();
883 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
884 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000885
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000886 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700887 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000888 for (IFlowPath flowPathObj : allFlowPaths) {
889 if (flowPathObj == null)
890 continue;
891 String flowIdStr = flowPathObj.getFlowId();
892 if (flowIdStr == null)
893 continue;
894 FlowId flowId = new FlowId(flowIdStr);
895 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000896 }
897
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000898 // Delete all flows one-by-one
899 for (FlowId flowId : concurrentAllFlowIds)
900 deleteFlow(flowId);
901
902 /*
903 * TODO: A faster mechanism to delete the Flow Paths by using
904 * a number of threads. Commented-out for now.
905 */
906 /*
907 //
908 // Create the threads to delete the Flow Paths
909 //
910 for (int i = 0; i < 10; i++) {
911 Thread thread = new Thread(new Runnable() {
912 @Override
913 public void run() {
914 while (true) {
915 FlowId flowId = concurrentAllFlowIds.poll();
916 if (flowId == null)
917 return;
918 deleteFlow(flowId);
919 }
920 }}, "Delete All Flow Paths");
921 threads.add(thread);
922 }
923
924 // Start processing
925 for (Thread thread : threads) {
926 thread.start();
927 }
928
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000929 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000930 for (Thread thread : threads) {
931 try {
932 thread.join();
933 } catch (InterruptedException e) {
934 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
935 }
936 }
937 */
938
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000939 return true;
940 }
941
942 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800943 * Delete a previously added flow.
944 *
945 * @param flowId the Flow ID of the flow to delete.
946 * @return true on success, otherwise false.
947 */
948 @Override
949 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700950 /*
951 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700952 if (flowId.value() == measurementFlowId) {
953 modifiedMeasurementFlowTime = System.nanoTime();
954 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700955 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700956
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800957 IFlowPath flowObj = null;
958 //
959 // We just mark the entries for deletion,
960 // and let the switches remove each individual entry after
961 // it has been removed from the switches.
962 //
963 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700964 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800965 != null) {
966 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
967 flowId.toString());
968 } else {
969 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
970 flowId.toString());
971 }
972 } catch (Exception e) {
973 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700974 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800975 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
976 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700977 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700978 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800979 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700980 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800981
982 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000983 // Find and mark for deletion all Flow Entries,
984 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800985 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000986 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800987 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
988 boolean empty = true; // TODO: an ugly hack
989 for (IFlowEntry flowEntryObj : flowEntries) {
990 empty = false;
991 // flowObj.removeFlowEntry(flowEntryObj);
992 // conn.utils().removeFlowEntry(conn, flowEntryObj);
993 flowEntryObj.setUserState("FE_USER_DELETE");
994 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
995 }
996 // Remove from the database empty flows
997 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700998 op.removeFlowPath(flowObj);
999 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001000
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001001 return true;
1002 }
1003
1004 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001005 * Clear the state for all previously added flows.
1006 *
1007 * @return true on success, otherwise false.
1008 */
1009 @Override
1010 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001011 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001012
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001013 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001014 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001015 for (IFlowPath flowPathObj : allFlowPaths) {
1016 if (flowPathObj == null)
1017 continue;
1018 String flowIdStr = flowPathObj.getFlowId();
1019 if (flowIdStr == null)
1020 continue;
1021 FlowId flowId = new FlowId(flowIdStr);
1022 allFlowIds.add(flowId);
1023 }
1024
1025 // Clear all flows one-by-one
1026 for (FlowId flowId : allFlowIds) {
1027 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001028 }
1029
1030 return true;
1031 }
1032
1033 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001034 * Clear the state for a previously added flow.
1035 *
1036 * @param flowId the Flow ID of the flow to clear.
1037 * @return true on success, otherwise false.
1038 */
1039 @Override
1040 public boolean clearFlow(FlowId flowId) {
1041 IFlowPath flowObj = null;
1042 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001043 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001044 != null) {
1045 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1046 flowId.toString());
1047 } else {
1048 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1049 flowId.toString());
1050 }
1051 } catch (Exception e) {
1052 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001053 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001054 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1055 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001056 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001057 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001058 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001059 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001060
1061 //
1062 // Remove all Flow Entries
1063 //
1064 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1065 for (IFlowEntry flowEntryObj : flowEntries) {
1066 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001067 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001068 }
1069 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001070 op.removeFlowPath(flowObj);
1071 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001072
1073 return true;
1074 }
1075
1076 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001077 * Get a previously added flow.
1078 *
1079 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001080 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001081 */
1082 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001083 public FlowPath getFlow(FlowId flowId) {
1084 IFlowPath flowObj = null;
1085 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001086 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001087 != null) {
1088 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1089 flowId.toString());
1090 } else {
1091 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1092 flowId.toString());
1093 }
1094 } catch (Exception e) {
1095 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001096 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001097 log.error(":getFlow FlowId:{} failed", flowId.toString());
1098 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001099 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001100 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001101 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001102 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001103
1104 //
1105 // Extract the Flow state
1106 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001107 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001108 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001109
1110 return flowPath;
1111 }
1112
1113 /**
1114 * Get all previously added flows by a specific installer for a given
1115 * data path endpoints.
1116 *
1117 * @param installerId the Caller ID of the installer of the flow to get.
1118 * @param dataPathEndpoints the data path endpoints of the flow to get.
1119 * @return the Flow Paths if found, otherwise null.
1120 */
1121 @Override
1122 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1123 DataPathEndpoints dataPathEndpoints) {
1124 //
1125 // TODO: The implementation below is not optimal:
1126 // We fetch all flows, and then return only the subset that match
1127 // the query conditions.
1128 // We should use the appropriate Titan/Gremlin query to filter-out
1129 // the flows as appropriate.
1130 //
1131 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001132 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001133
1134 if (allFlows == null) {
1135 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001136 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001137 }
1138
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001139 for (FlowPath flow : allFlows) {
1140 //
1141 // TODO: String-based comparison is sub-optimal.
1142 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001143 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001144 //
1145 if (! flow.installerId().toString().equals(installerId.toString()))
1146 continue;
1147 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1148 continue;
1149 }
1150 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1151 continue;
1152 }
1153 flowPaths.add(flow);
1154 }
1155
1156 if (flowPaths.isEmpty()) {
1157 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001158 } else {
1159 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1160 }
1161
1162 return flowPaths;
1163 }
1164
1165 /**
1166 * Get all installed flows by all installers for given data path endpoints.
1167 *
1168 * @param dataPathEndpoints the data path endpoints of the flows to get.
1169 * @return the Flow Paths if found, otherwise null.
1170 */
1171 @Override
1172 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1173 //
1174 // TODO: The implementation below is not optimal:
1175 // We fetch all flows, and then return only the subset that match
1176 // the query conditions.
1177 // We should use the appropriate Titan/Gremlin query to filter-out
1178 // the flows as appropriate.
1179 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001180 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1181 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001182
1183 if (allFlows == null) {
1184 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001185 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001186 }
1187
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001188 for (FlowPath flow : allFlows) {
1189 //
1190 // TODO: String-based comparison is sub-optimal.
1191 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001192 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001193 //
1194 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1195 continue;
1196 }
1197 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1198 continue;
1199 }
1200 flowPaths.add(flow);
1201 }
1202
1203 if (flowPaths.isEmpty()) {
1204 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001205 } else {
1206 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1207 }
1208
1209 return flowPaths;
1210 }
1211
1212 /**
admin944ef4f2013-10-08 17:48:37 -07001213 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001214 *
admin944ef4f2013-10-08 17:48:37 -07001215 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001216 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001217 * @return the Flow Paths if found, otherwise null.
1218 */
1219 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001220 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001221
admin944ef4f2013-10-08 17:48:37 -07001222 //
1223 // TODO: The implementation below is not optimal:
1224 // We fetch all flows, and then return only the subset that match
1225 // the query conditions.
1226 // We should use the appropriate Titan/Gremlin query to filter-out
1227 // the flows as appropriate.
1228 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001229 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001230
Jonathan Hart01f2d272013-04-04 20:03:46 -07001231 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1232
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001233 Collections.sort(flowPathsWithoutFlowEntries,
1234 new Comparator<IFlowPath>(){
1235 @Override
1236 public int compare(IFlowPath first, IFlowPath second) {
1237 // TODO Auto-generated method stub
1238 long result = new FlowId(first.getFlowId()).value()
1239 - new FlowId(second.getFlowId()).value();
1240 if (result > 0) return 1;
1241 else if (result < 0) return -1;
1242 else return 0;
1243 }
1244 }
1245 );
1246
Jonathan Hart01f2d272013-04-04 20:03:46 -07001247 return flowPathsWithoutFlowEntries;
1248
1249 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001250 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001251
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001252 if (allFlows == null) {
1253 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001254 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001255 }
1256
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001257 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001258
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001259 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001260 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001261
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001262 // start from desired flowId
1263 if (flow.flowId().value() < flowId.value()) {
1264 continue;
1265 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001266
1267 // Summarize by making null flow entry fields that are not relevant to report
1268 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1269 flowEntry.setFlowEntryActions(null);
1270 flowEntry.setFlowEntryMatch(null);
1271 }
1272
1273 flowPaths.add(flow);
1274 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1275 break;
1276 }
1277 }
1278
1279 if (flowPaths.isEmpty()) {
1280 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001281 } else {
1282 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1283 }
1284
1285 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001286 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001287 }
1288
1289 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001290 * Get all installed flows by all installers.
1291 *
1292 * @return the Flow Paths if found, otherwise null.
1293 */
1294 @Override
1295 public ArrayList<FlowPath> getAllFlows() {
1296 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001297 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001298
1299 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001300 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001301 log.debug("Get all FlowPaths: found FlowPaths");
1302 } else {
1303 log.debug("Get all FlowPaths: no FlowPaths found");
1304 }
1305 } catch (Exception e) {
1306 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001307 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001308 log.error(":getAllFlowPaths failed");
1309 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001310 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001311 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001312 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001313 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001314
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001315 for (IFlowPath flowObj : flowPathsObj) {
1316 //
1317 // Extract the Flow state
1318 //
1319 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001320 if (flowPath != null)
1321 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001322 }
1323
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001324 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001325
1326 return flowPaths;
1327 }
admin944ef4f2013-10-08 17:48:37 -07001328
1329 /**
1330 * Get all Flows information, without the associated Flow Entries.
1331 *
1332 * @return all Flows information, without the associated Flow Entries.
1333 */
1334 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001335 Iterable<IFlowPath> flowPathsObj = null;
1336 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1337 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1338
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001339 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001340
Jonathan Hart01f2d272013-04-04 20:03:46 -07001341 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001342 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001343 log.debug("Get all FlowPaths: found FlowPaths");
1344 } else {
1345 log.debug("Get all FlowPaths: no FlowPaths found");
1346 }
1347 } catch (Exception e) {
1348 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001349 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001350 log.error(":getAllFlowPaths failed");
1351 }
1352 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1353 return new ArrayList<IFlowPath>(); // No Flows found
1354 }
1355
1356 for (IFlowPath flowObj : flowPathsObj){
1357 flowPathsObjArray.add(flowObj);
1358 }
1359 /*
1360 for (IFlowPath flowObj : flowPathsObj) {
1361 //
1362 // Extract the Flow state
1363 //
1364 FlowPath flowPath = extractFlowPath(flowObj);
1365 if (flowPath != null)
1366 flowPaths.add(flowPath);
1367 }
1368 */
1369
1370 //conn.endTx(Transaction.COMMIT);
1371
1372 return flowPathsObjArray;
1373 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001374
1375 /**
1376 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1377 *
1378 * @param flowObj the object to extract the Flow Path State from.
1379 * @return the extracted Flow Path State.
1380 */
1381 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001382 //
1383 // Extract the Flow state
1384 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001385 String flowIdStr = flowObj.getFlowId();
1386 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001387 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001388 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001389 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001390 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001391 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001392
1393 if ((flowIdStr == null) ||
1394 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001395 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001396 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001397 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001398 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001399 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001400 // TODO: A work-around, becauuse of some bogus database objects
1401 return null;
1402 }
1403
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001404 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001405 flowPath.setFlowId(new FlowId(flowIdStr));
1406 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001407 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001408 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001409 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001410 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001411 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001412 //
1413 // Extract the match conditions common for all Flow Entries
1414 //
1415 {
1416 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001417 String matchSrcMac = flowObj.getMatchSrcMac();
1418 if (matchSrcMac != null)
1419 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1420 String matchDstMac = flowObj.getMatchDstMac();
1421 if (matchDstMac != null)
1422 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001423 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1424 if (matchEthernetFrameType != null)
1425 match.enableEthernetFrameType(matchEthernetFrameType);
1426 Short matchVlanId = flowObj.getMatchVlanId();
1427 if (matchVlanId != null)
1428 match.enableVlanId(matchVlanId);
1429 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1430 if (matchVlanPriority != null)
1431 match.enableVlanPriority(matchVlanPriority);
1432 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1433 if (matchSrcIPv4Net != null)
1434 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1435 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1436 if (matchDstIPv4Net != null)
1437 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1438 Byte matchIpProto = flowObj.getMatchIpProto();
1439 if (matchIpProto != null)
1440 match.enableIpProto(matchIpProto);
1441 Byte matchIpToS = flowObj.getMatchIpToS();
1442 if (matchIpToS != null)
1443 match.enableIpToS(matchIpToS);
1444 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1445 if (matchSrcTcpUdpPort != null)
1446 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1447 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1448 if (matchDstTcpUdpPort != null)
1449 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1450
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001451 flowPath.setFlowEntryMatch(match);
1452 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001453 //
1454 // Extract the actions for the first Flow Entry
1455 //
1456 {
1457 String actionsStr = flowObj.getActions();
1458 if (actionsStr != null) {
1459 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1460 flowPath.setFlowEntryActions(flowEntryActions);
1461 }
1462 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001463
1464 //
1465 // Extract all Flow Entries
1466 //
1467 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1468 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001469 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1470 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001471 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001472 flowPath.dataPath().flowEntries().add(flowEntry);
1473 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001474
1475 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001476 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001477
1478 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001479 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1480 *
1481 * @param flowEntryObj the object to extract the Flow Entry State from.
1482 * @return the extracted Flow Entry State.
1483 */
1484 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1485 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1486 String switchDpidStr = flowEntryObj.getSwitchDpid();
1487 String userState = flowEntryObj.getUserState();
1488 String switchState = flowEntryObj.getSwitchState();
1489
1490 if ((flowEntryIdStr == null) ||
1491 (switchDpidStr == null) ||
1492 (userState == null) ||
1493 (switchState == null)) {
1494 // TODO: A work-around, becauuse of some bogus database objects
1495 return null;
1496 }
1497
1498 FlowEntry flowEntry = new FlowEntry();
1499 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1500 flowEntry.setDpid(new Dpid(switchDpidStr));
1501
1502 //
1503 // Extract the match conditions
1504 //
1505 FlowEntryMatch match = new FlowEntryMatch();
1506 Short matchInPort = flowEntryObj.getMatchInPort();
1507 if (matchInPort != null)
1508 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001509 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1510 if (matchSrcMac != null)
1511 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1512 String matchDstMac = flowEntryObj.getMatchDstMac();
1513 if (matchDstMac != null)
1514 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001515 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1516 if (matchEthernetFrameType != null)
1517 match.enableEthernetFrameType(matchEthernetFrameType);
1518 Short matchVlanId = flowEntryObj.getMatchVlanId();
1519 if (matchVlanId != null)
1520 match.enableVlanId(matchVlanId);
1521 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1522 if (matchVlanPriority != null)
1523 match.enableVlanPriority(matchVlanPriority);
1524 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1525 if (matchSrcIPv4Net != null)
1526 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1527 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1528 if (matchDstIPv4Net != null)
1529 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1530 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1531 if (matchIpProto != null)
1532 match.enableIpProto(matchIpProto);
1533 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1534 if (matchIpToS != null)
1535 match.enableIpToS(matchIpToS);
1536 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1537 if (matchSrcTcpUdpPort != null)
1538 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1539 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1540 if (matchDstTcpUdpPort != null)
1541 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001542 flowEntry.setFlowEntryMatch(match);
1543
1544 //
1545 // Extract the actions
1546 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001547 FlowEntryActions actions = new FlowEntryActions();
1548 String actionsStr = flowEntryObj.getActions();
1549 if (actionsStr != null)
1550 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001551 flowEntry.setFlowEntryActions(actions);
1552 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1553 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1554 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001555 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001556 //
1557 return flowEntry;
1558 }
1559
1560 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001561 * Add and maintain a shortest-path flow.
1562 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001563 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001564 *
1565 * @param flowPath the Flow Path with the endpoints and the match
1566 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001567 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001568 */
1569 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001570 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001571 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001572 // Don't do the shortest path computation here.
1573 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001574 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001575
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001576 // We need the DataPath to populate the Network MAP
1577 DataPath dataPath = new DataPath();
1578 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1579 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001580
1581 //
1582 // Prepare the computed Flow Path
1583 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001584 FlowPath computedFlowPath = new FlowPath();
1585 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1586 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001587 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001588 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001589 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001590 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001591
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001592 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001593 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001594 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001595 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001596
1597 // TODO: Mark the flow for maintenance purpose
1598
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001599 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001600 }
1601
1602 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001603 * Reconcile a flow.
1604 *
1605 * @param flowObj the flow that needs to be reconciliated.
1606 * @param newDataPath the new data path to use.
1607 * @return true on success, otherwise false.
1608 */
1609 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1610 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1611
1612 //
1613 // Set the incoming port matching and the outgoing port output
1614 // actions for each flow entry.
1615 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001616 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001617 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1618 // Set the incoming port matching
1619 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1620 flowEntry.setFlowEntryMatch(flowEntryMatch);
1621 flowEntryMatch.enableInPort(flowEntry.inPort());
1622
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001623 //
1624 // Set the actions
1625 //
1626 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1627 //
1628 // If the first Flow Entry, copy the Flow Path actions to it
1629 //
1630 if (idx == 0) {
1631 String actionsStr = flowObj.getActions();
1632 if (actionsStr != null) {
1633 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1634 for (FlowEntryAction action : flowActions.actions())
1635 flowEntryActions.addAction(action);
1636 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001637 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001638 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001639 //
1640 // Add the outgoing port output action
1641 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001642 FlowEntryAction flowEntryAction = new FlowEntryAction();
1643 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001644 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001645 }
1646
1647 //
1648 // Remove the old Flow Entries, and add the new Flow Entries
1649 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001650 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1651 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1652 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001653 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001654 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001655 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001656 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001657 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001658 }
1659
1660 //
1661 // Set the Data Path Summary
1662 //
1663 String dataPathSummaryStr = newDataPath.dataPathSummary();
1664 flowObj.setDataPathSummary(dataPathSummaryStr);
1665
1666 return true;
1667 }
1668
1669 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001670 * Reconcile all flows in a set.
1671 *
1672 * @param flowObjSet the set of flows that need to be reconciliated.
1673 */
1674 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1675 if (! flowObjSet.iterator().hasNext())
1676 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001677 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001678 }
1679
1680 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001681 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001682 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001683 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001684 * @param flowObj the flow path object for the flow entry to install.
1685 * @param flowEntryObj the flow entry object to install.
1686 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001687 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001688 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1689 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001690 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1691 if (flowEntryIdStr == null)
1692 return false;
1693 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001694 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001695 if (userState == null)
1696 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001697
1698 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001699 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001700 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001701 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1702 .getMessage(OFType.FLOW_MOD);
1703 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001704
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001705 short flowModCommand = OFFlowMod.OFPFC_ADD;
1706 if (userState.equals("FE_USER_ADD")) {
1707 flowModCommand = OFFlowMod.OFPFC_ADD;
1708 } else if (userState.equals("FE_USER_MODIFY")) {
1709 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1710 } else if (userState.equals("FE_USER_DELETE")) {
1711 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1712 } else {
1713 // Unknown user state. Ignore the entry
1714 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1715 flowEntryId.toString(), userState);
1716 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001717 }
1718
1719 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001720 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001721 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001722 // NOTE: The Flow matching conditions common for all Flow Entries are
1723 // used ONLY if a Flow Entry does NOT have the corresponding matching
1724 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001725 //
1726 OFMatch match = new OFMatch();
1727 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001728
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001729 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001730 Short matchInPort = flowEntryObj.getMatchInPort();
1731 if (matchInPort != null) {
1732 match.setInputPort(matchInPort);
1733 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1734 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001735
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001736 // Match the Source MAC address
1737 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1738 if (matchSrcMac == null)
1739 matchSrcMac = flowObj.getMatchSrcMac();
1740 if (matchSrcMac != null) {
1741 match.setDataLayerSource(matchSrcMac);
1742 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1743 }
1744
1745 // Match the Destination MAC address
1746 String matchDstMac = flowEntryObj.getMatchDstMac();
1747 if (matchDstMac == null)
1748 matchDstMac = flowObj.getMatchDstMac();
1749 if (matchDstMac != null) {
1750 match.setDataLayerDestination(matchDstMac);
1751 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1752 }
1753
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001754 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001755 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1756 if (matchEthernetFrameType == null)
1757 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1758 if (matchEthernetFrameType != null) {
1759 match.setDataLayerType(matchEthernetFrameType);
1760 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1761 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001762
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001763 // Match the VLAN ID
1764 Short matchVlanId = flowEntryObj.getMatchVlanId();
1765 if (matchVlanId == null)
1766 matchVlanId = flowObj.getMatchVlanId();
1767 if (matchVlanId != null) {
1768 match.setDataLayerVirtualLan(matchVlanId);
1769 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1770 }
1771
1772 // Match the VLAN priority
1773 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1774 if (matchVlanPriority == null)
1775 matchVlanPriority = flowObj.getMatchVlanPriority();
1776 if (matchVlanPriority != null) {
1777 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1778 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1779 }
1780
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001781 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001782 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1783 if (matchSrcIPv4Net == null)
1784 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1785 if (matchSrcIPv4Net != null) {
1786 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1787 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001788
1789 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001790 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1791 if (matchDstIPv4Net == null)
1792 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1793 if (matchDstIPv4Net != null) {
1794 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1795 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001796
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001797 // Match the IP protocol
1798 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1799 if (matchIpProto == null)
1800 matchIpProto = flowObj.getMatchIpProto();
1801 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001802 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001803 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001804 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001805
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001806 // Match the IP ToS (DSCP field, 6 bits)
1807 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1808 if (matchIpToS == null)
1809 matchIpToS = flowObj.getMatchIpToS();
1810 if (matchIpToS != null) {
1811 match.setNetworkTypeOfService(matchIpToS);
1812 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1813 }
1814
1815 // Match the Source TCP/UDP port
1816 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1817 if (matchSrcTcpUdpPort == null)
1818 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1819 if (matchSrcTcpUdpPort != null) {
1820 match.setTransportSource(matchSrcTcpUdpPort);
1821 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1822 }
1823
1824 // Match the Destination TCP/UDP port
1825 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1826 if (matchDstTcpUdpPort == null)
1827 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1828 if (matchDstTcpUdpPort != null) {
1829 match.setTransportDestination(matchDstTcpUdpPort);
1830 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001831 }
1832
1833 //
1834 // Fetch the actions
1835 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001836 Short actionOutputPort = null;
1837 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1838 int actionsLen = 0;
1839 FlowEntryActions flowEntryActions = null;
1840 String actionsStr = flowEntryObj.getActions();
1841 if (actionsStr != null)
1842 flowEntryActions = new FlowEntryActions(actionsStr);
1843 for (FlowEntryAction action : flowEntryActions.actions()) {
1844 ActionOutput actionOutput = action.actionOutput();
1845 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1846 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1847 ActionStripVlan actionStripVlan = action.actionStripVlan();
1848 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1849 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1850 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1851 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1852 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1853 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1854 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1855 ActionEnqueue actionEnqueue = action.actionEnqueue();
1856
1857 if (actionOutput != null) {
1858 actionOutputPort = actionOutput.port().value();
1859 // XXX: The max length is hard-coded for now
1860 OFActionOutput ofa =
1861 new OFActionOutput(actionOutput.port().value(),
1862 (short)0xffff);
1863 openFlowActions.add(ofa);
1864 actionsLen += ofa.getLength();
1865 }
1866
1867 if (actionSetVlanId != null) {
1868 OFActionVirtualLanIdentifier ofa =
1869 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1870 openFlowActions.add(ofa);
1871 actionsLen += ofa.getLength();
1872 }
1873
1874 if (actionSetVlanPriority != null) {
1875 OFActionVirtualLanPriorityCodePoint ofa =
1876 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1877 openFlowActions.add(ofa);
1878 actionsLen += ofa.getLength();
1879 }
1880
1881 if (actionStripVlan != null) {
1882 if (actionStripVlan.stripVlan() == true) {
1883 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1884 openFlowActions.add(ofa);
1885 actionsLen += ofa.getLength();
1886 }
1887 }
1888
1889 if (actionSetEthernetSrcAddr != null) {
1890 OFActionDataLayerSource ofa =
1891 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1892 openFlowActions.add(ofa);
1893 actionsLen += ofa.getLength();
1894 }
1895
1896 if (actionSetEthernetDstAddr != null) {
1897 OFActionDataLayerDestination ofa =
1898 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1899 openFlowActions.add(ofa);
1900 actionsLen += ofa.getLength();
1901 }
1902
1903 if (actionSetIPv4SrcAddr != null) {
1904 OFActionNetworkLayerSource ofa =
1905 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1906 openFlowActions.add(ofa);
1907 actionsLen += ofa.getLength();
1908 }
1909
1910 if (actionSetIPv4DstAddr != null) {
1911 OFActionNetworkLayerDestination ofa =
1912 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1913 openFlowActions.add(ofa);
1914 actionsLen += ofa.getLength();
1915 }
1916
1917 if (actionSetIpToS != null) {
1918 OFActionNetworkTypeOfService ofa =
1919 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1920 openFlowActions.add(ofa);
1921 actionsLen += ofa.getLength();
1922 }
1923
1924 if (actionSetTcpUdpSrcPort != null) {
1925 OFActionTransportLayerSource ofa =
1926 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1927 openFlowActions.add(ofa);
1928 actionsLen += ofa.getLength();
1929 }
1930
1931 if (actionSetTcpUdpDstPort != null) {
1932 OFActionTransportLayerDestination ofa =
1933 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1934 openFlowActions.add(ofa);
1935 actionsLen += ofa.getLength();
1936 }
1937
1938 if (actionEnqueue != null) {
1939 OFActionEnqueue ofa =
1940 new OFActionEnqueue(actionEnqueue.port().value(),
1941 actionEnqueue.queueId());
1942 openFlowActions.add(ofa);
1943 actionsLen += ofa.getLength();
1944 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001945 }
1946
1947 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1948 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1949 .setPriority(PRIORITY_DEFAULT)
1950 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1951 .setCookie(cookie)
1952 .setCommand(flowModCommand)
1953 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001954 .setActions(openFlowActions)
1955 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001956 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1957 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1958 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1959 if (actionOutputPort != null)
1960 fm.setOutPort(actionOutputPort);
1961 }
1962
1963 //
1964 // TODO: Set the following flag
1965 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1966 // See method ForwardingBase::pushRoute()
1967 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001968
1969 //
1970 // Write the message to the switch
1971 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001972 log.debug("MEASUREMENT: Installing flow entry " + userState +
1973 " into switch DPID: " +
1974 mySwitch.getStringId() +
1975 " flowEntryId: " + flowEntryId.toString() +
1976 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1977 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1978 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001979 try {
1980 messageDamper.write(mySwitch, fm, null);
1981 mySwitch.flush();
1982 //
1983 // TODO: We should use the OpenFlow Barrier mechanism
1984 // to check for errors, and update the SwitchState
1985 // for a flow entry after the Barrier message is
1986 // is received.
1987 //
1988 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1989 } catch (IOException e) {
1990 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001991 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001992 }
1993
1994 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001995 }
1996
1997 /**
1998 * Install a Flow Entry on a switch.
1999 *
2000 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002001 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002002 * @param flowEntry the flow entry to install.
2003 * @return true on success, otherwise false.
2004 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002005 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2006 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002007 //
2008 // Create the OpenFlow Flow Modification Entry to push
2009 //
2010 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
2011 .getMessage(OFType.FLOW_MOD);
2012 long cookie = flowEntry.flowEntryId().value();
2013
2014 short flowModCommand = OFFlowMod.OFPFC_ADD;
2015 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
2016 flowModCommand = OFFlowMod.OFPFC_ADD;
2017 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
2018 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
2019 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
2020 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
2021 } else {
2022 // Unknown user state. Ignore the entry
2023 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
2024 flowEntry.flowEntryId().toString(),
2025 flowEntry.flowEntryUserState());
2026 return false;
2027 }
2028
2029 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002030 // Fetch the match conditions.
2031 //
2032 // NOTE: The Flow matching conditions common for all Flow Entries are
2033 // used ONLY if a Flow Entry does NOT have the corresponding matching
2034 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002035 //
2036 OFMatch match = new OFMatch();
2037 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002038 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
2039 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
2040
2041 // Match the Incoming Port
2042 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002043 if (matchInPort != null) {
2044 match.setInputPort(matchInPort.value());
2045 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
2046 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002047
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002048 // Match the Source MAC address
2049 MACAddress matchSrcMac = flowEntryMatch.srcMac();
2050 if ((matchSrcMac == null) && (flowPathMatch != null)) {
2051 matchSrcMac = flowPathMatch.srcMac();
2052 }
2053 if (matchSrcMac != null) {
2054 match.setDataLayerSource(matchSrcMac.toString());
2055 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2056 }
2057
2058 // Match the Destination MAC address
2059 MACAddress matchDstMac = flowEntryMatch.dstMac();
2060 if ((matchDstMac == null) && (flowPathMatch != null)) {
2061 matchDstMac = flowPathMatch.dstMac();
2062 }
2063 if (matchDstMac != null) {
2064 match.setDataLayerDestination(matchDstMac.toString());
2065 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2066 }
2067
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002068 // Match the Ethernet Frame Type
2069 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2070 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2071 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2072 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002073 if (matchEthernetFrameType != null) {
2074 match.setDataLayerType(matchEthernetFrameType);
2075 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2076 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002077
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002078 // Match the VLAN ID
2079 Short matchVlanId = flowEntryMatch.vlanId();
2080 if ((matchVlanId == null) && (flowPathMatch != null)) {
2081 matchVlanId = flowPathMatch.vlanId();
2082 }
2083 if (matchVlanId != null) {
2084 match.setDataLayerVirtualLan(matchVlanId);
2085 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2086 }
2087
2088 // Match the VLAN priority
2089 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2090 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2091 matchVlanPriority = flowPathMatch.vlanPriority();
2092 }
2093 if (matchVlanPriority != null) {
2094 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2095 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2096 }
2097
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002098 // Match the Source IPv4 Network prefix
2099 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2100 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2101 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2102 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002103 if (matchSrcIPv4Net != null) {
2104 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2105 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002106
2107 // Natch the Destination IPv4 Network prefix
2108 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2109 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2110 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2111 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002112 if (matchDstIPv4Net != null) {
2113 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2114 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002115
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002116 // Match the IP protocol
2117 Byte matchIpProto = flowEntryMatch.ipProto();
2118 if ((matchIpProto == null) && (flowPathMatch != null)) {
2119 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002120 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002121 if (matchIpProto != null) {
2122 match.setNetworkProtocol(matchIpProto);
2123 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002124 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002125
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002126 // Match the IP ToS (DSCP field, 6 bits)
2127 Byte matchIpToS = flowEntryMatch.ipToS();
2128 if ((matchIpToS == null) && (flowPathMatch != null)) {
2129 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002130 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002131 if (matchIpToS != null) {
2132 match.setNetworkTypeOfService(matchIpToS);
2133 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2134 }
2135
2136 // Match the Source TCP/UDP port
2137 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2138 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2139 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2140 }
2141 if (matchSrcTcpUdpPort != null) {
2142 match.setTransportSource(matchSrcTcpUdpPort);
2143 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2144 }
2145
2146 // Match the Destination TCP/UDP port
2147 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2148 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2149 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2150 }
2151 if (matchDstTcpUdpPort != null) {
2152 match.setTransportDestination(matchDstTcpUdpPort);
2153 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002154 }
2155
2156 //
2157 // Fetch the actions
2158 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002159 Short actionOutputPort = null;
2160 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2161 int actionsLen = 0;
2162 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002163 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002164 for (FlowEntryAction action : flowEntryActions.actions()) {
2165 ActionOutput actionOutput = action.actionOutput();
2166 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2167 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2168 ActionStripVlan actionStripVlan = action.actionStripVlan();
2169 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2170 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2171 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2172 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2173 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2174 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2175 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2176 ActionEnqueue actionEnqueue = action.actionEnqueue();
2177
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002178 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002179 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002180 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002181 OFActionOutput ofa =
2182 new OFActionOutput(actionOutput.port().value(),
2183 (short)0xffff);
2184 openFlowActions.add(ofa);
2185 actionsLen += ofa.getLength();
2186 }
2187
2188 if (actionSetVlanId != null) {
2189 OFActionVirtualLanIdentifier ofa =
2190 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2191 openFlowActions.add(ofa);
2192 actionsLen += ofa.getLength();
2193 }
2194
2195 if (actionSetVlanPriority != null) {
2196 OFActionVirtualLanPriorityCodePoint ofa =
2197 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2198 openFlowActions.add(ofa);
2199 actionsLen += ofa.getLength();
2200 }
2201
2202 if (actionStripVlan != null) {
2203 if (actionStripVlan.stripVlan() == true) {
2204 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2205 openFlowActions.add(ofa);
2206 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002207 }
2208 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002209
2210 if (actionSetEthernetSrcAddr != null) {
2211 OFActionDataLayerSource ofa =
2212 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2213 openFlowActions.add(ofa);
2214 actionsLen += ofa.getLength();
2215 }
2216
2217 if (actionSetEthernetDstAddr != null) {
2218 OFActionDataLayerDestination ofa =
2219 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2220 openFlowActions.add(ofa);
2221 actionsLen += ofa.getLength();
2222 }
2223
2224 if (actionSetIPv4SrcAddr != null) {
2225 OFActionNetworkLayerSource ofa =
2226 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2227 openFlowActions.add(ofa);
2228 actionsLen += ofa.getLength();
2229 }
2230
2231 if (actionSetIPv4DstAddr != null) {
2232 OFActionNetworkLayerDestination ofa =
2233 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2234 openFlowActions.add(ofa);
2235 actionsLen += ofa.getLength();
2236 }
2237
2238 if (actionSetIpToS != null) {
2239 OFActionNetworkTypeOfService ofa =
2240 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2241 openFlowActions.add(ofa);
2242 actionsLen += ofa.getLength();
2243 }
2244
2245 if (actionSetTcpUdpSrcPort != null) {
2246 OFActionTransportLayerSource ofa =
2247 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2248 openFlowActions.add(ofa);
2249 actionsLen += ofa.getLength();
2250 }
2251
2252 if (actionSetTcpUdpDstPort != null) {
2253 OFActionTransportLayerDestination ofa =
2254 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2255 openFlowActions.add(ofa);
2256 actionsLen += ofa.getLength();
2257 }
2258
2259 if (actionEnqueue != null) {
2260 OFActionEnqueue ofa =
2261 new OFActionEnqueue(actionEnqueue.port().value(),
2262 actionEnqueue.queueId());
2263 openFlowActions.add(ofa);
2264 actionsLen += ofa.getLength();
2265 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002266 }
2267
2268 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2269 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2270 .setPriority(PRIORITY_DEFAULT)
2271 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2272 .setCookie(cookie)
2273 .setCommand(flowModCommand)
2274 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002275 .setActions(openFlowActions)
2276 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2277 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2278 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2279 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2280 if (actionOutputPort != null)
2281 fm.setOutPort(actionOutputPort);
2282 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002283
2284 //
2285 // TODO: Set the following flag
2286 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2287 // See method ForwardingBase::pushRoute()
2288 //
2289
2290 //
2291 // Write the message to the switch
2292 //
2293 try {
2294 messageDamper.write(mySwitch, fm, null);
2295 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002296 //
2297 // TODO: We should use the OpenFlow Barrier mechanism
2298 // to check for errors, and update the SwitchState
2299 // for a flow entry after the Barrier message is
2300 // is received.
2301 //
2302 // TODO: The FlowEntry Object in Titan should be set
2303 // to FE_SWITCH_UPDATED.
2304 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002305 } catch (IOException e) {
2306 log.error("Failure writing flow mod from network map", e);
2307 return false;
2308 }
2309 return true;
2310 }
2311
2312 /**
2313 * Remove a Flow Entry from a switch.
2314 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002315 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002316 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002317 * @param flowEntry the flow entry to remove.
2318 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002319 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002320 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2321 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002322 //
2323 // The installFlowEntry() method implements both installation
2324 // and removal of flow entries.
2325 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002326 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002327 }
2328
2329 /**
2330 * Install a Flow Entry on a remote controller.
2331 *
2332 * TODO: We need it now: Jono
2333 * - For now it will make a REST call to the remote controller.
2334 * - Internally, it needs to know the name of the remote controller.
2335 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002336 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002337 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002338 * @return true on success, otherwise false.
2339 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002340 public boolean installRemoteFlowEntry(FlowPath flowPath,
2341 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002342 // TODO: We need it now: Jono
2343 // - For now it will make a REST call to the remote controller.
2344 // - Internally, it needs to know the name of the remote controller.
2345 return true;
2346 }
2347
2348 /**
2349 * Remove a flow entry on a remote controller.
2350 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002351 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002352 * @param flowEntry the flow entry to remove.
2353 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002354 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002355 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2356 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002357 //
2358 // The installRemoteFlowEntry() method implements both installation
2359 // and removal of flow entries.
2360 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002361 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002362 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002363}