blob: 969d41e639f2dbb6066f48d7af2b65bf7cace1e6 [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;
Pankaj Berde38646d62013-06-21 11:34:04 -070030import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070031import net.onrc.onos.ofcontroller.core.INetMapStorage;
32import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
33import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
36import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070037import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070038import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070039import net.onrc.onos.ofcontroller.util.CallerId;
40import net.onrc.onos.ofcontroller.util.DataPath;
41import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
42import net.onrc.onos.ofcontroller.util.Dpid;
43import net.onrc.onos.ofcontroller.util.FlowEntry;
44import net.onrc.onos.ofcontroller.util.FlowEntryAction;
45import net.onrc.onos.ofcontroller.util.FlowEntryId;
46import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
47import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
48import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
49import net.onrc.onos.ofcontroller.util.FlowId;
50import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070051import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070052import net.onrc.onos.ofcontroller.util.IPv4Net;
53import net.onrc.onos.ofcontroller.util.Port;
54import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080055
56import org.openflow.protocol.OFFlowMod;
57import org.openflow.protocol.OFMatch;
58import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070059import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080060import org.openflow.protocol.OFType;
61import org.openflow.protocol.action.OFAction;
62import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
Jonathan Hartf5315fb2013-04-05 11:41:56 -070066
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070067public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068
Toshio Koide9fe1cb22013-06-13 13:51:11 -070069 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070
71 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070072 protected volatile IFloodlightProviderService floodlightProvider;
73 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070074 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075
76 protected OFMessageDamper messageDamper;
77
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070078 //
79 // TODO: Values copied from elsewhere (class LearningSwitch).
80 // The local copy should go away!
81 //
82 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
83 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
84 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
85 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
86 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080087
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000088 // Flow Entry ID generation state
89 private static Random randomGenerator = new Random();
90 private static int nextFlowEntryIdPrefix = 0;
91 private static int nextFlowEntryIdSuffix = 0;
92 private static long nextFlowEntryId = 0;
93
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070094 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070095 private static long measurementFlowId = 100000;
96 private static String measurementFlowIdStr = "0x186a0"; // 100000
97 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070098 //
99 private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700100 private long measurementStartTimeProcessingPaths = 0;
101 private long measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000102 Map<Long, ?> measurementShortestPathTopo = null;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000103 private String measurementPerFlowStr = new String();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700104
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800105 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
107
108 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700109 private ScheduledExecutorService mapReaderScheduler;
110 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700111
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700112 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800113 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700114 try {
115 runImpl();
116 } catch (Exception e) {
117 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700118 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700119 return;
120 }
121 }
122
123 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700124 long startTime = System.nanoTime();
125 int counterAllFlowEntries = 0;
126 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700127
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800128 if (floodlightProvider == null) {
129 log.debug("FloodlightProvider service not found!");
130 return;
131 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000132 Map<Long, IOFSwitch> mySwitches =
133 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700134 LinkedList<IFlowEntry> addFlowEntries =
135 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000136 LinkedList<IFlowEntry> deleteFlowEntries =
137 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700138
139 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700140 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700141 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700142 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700143 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000144 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700145 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700146 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700147 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000148
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000149 String dpidStr = flowEntryObj.getSwitchDpid();
150 if (dpidStr == null)
151 continue;
152 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800153 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000154 if (mySwitch == null)
155 continue; // Ignore the entry: not my switch
156
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700158 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700159 if (flowObj == null)
160 continue; // Should NOT happen
161 if (flowObj.getFlowId() == null)
162 continue; // Invalid entry
163
164 //
165 // NOTE: For now we process the DELETE before the ADD
166 // to cover the more common scenario.
167 // TODO: This is error prone and needs to be fixed!
168 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000169 String userState = flowEntryObj.getUserState();
170 if (userState == null)
171 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700172 if (userState.equals("FE_USER_DELETE")) {
173 // An entry that needs to be deleted.
174 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700175 installFlowEntry(mySwitch, flowObj, flowEntryObj);
176 } else {
177 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700178 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700179 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700180 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700181 // TODO: Commented-out for now
182 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700183 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700184 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700185 processed_measurement_flow = true;
186 }
187 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700188 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700189 }
190
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700191 //
192 // Process the Flow Entries that need to be added
193 //
194 for (IFlowEntry flowEntryObj : addFlowEntries) {
195 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700196 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700197 if (flowObj == null)
198 continue; // Should NOT happen
199 if (flowObj.getFlowId() == null)
200 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700201
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700203 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204 if (mySwitch == null)
205 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700206 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800207 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000208
209 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000210 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700211 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000212 //
213 // TODO: We should use the OpenFlow Barrier mechanism
214 // to check for errors, and delete the Flow Entries after the
215 // Barrier message is received.
216 //
217 while (! deleteFlowEntries.isEmpty()) {
218 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
219 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700220 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000221 if (flowObj == null) {
222 log.debug("Did not find FlowPath to be deleted");
223 continue;
224 }
225 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700226 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000227 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700228
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700229 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700230
231 if (processed_measurement_flow) {
232 long estimatedTime =
233 System.nanoTime() - modifiedMeasurementFlowTime;
234 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
235 (double)estimatedTime / 1000000000 + " sec";
236 log.debug(logMsg);
237 }
238
239 long estimatedTime = System.nanoTime() - startTime;
240 double rate = 0.0;
241 if (estimatedTime > 0)
242 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
243 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
244 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
245 counterMyNotUpdatedFlowEntries + " in " +
246 (double)estimatedTime / 1000000000 + " sec: " +
247 rate + " paths/s";
248 log.debug(logMsg);
249 }
250 };
251
252 final Runnable shortestPathReconcile = new Runnable() {
253 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700254 try {
255 runImpl();
256 } catch (Exception e) {
257 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700258 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700259 return;
260 }
261 }
262
263 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700264 long startTime = System.nanoTime();
265 int counterAllFlowPaths = 0;
266 int counterMyFlowPaths = 0;
267
268 if (floodlightProvider == null) {
269 log.debug("FloodlightProvider service not found!");
270 return;
271 }
272 Map<Long, IOFSwitch> mySwitches =
273 floodlightProvider.getSwitches();
274 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
275
276 boolean processed_measurement_flow = false;
277
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700278 //
279 // Fetch and recompute the Shortest Path for those
280 // Flow Paths this controller is responsible for.
281 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000282 Map<Long, ?> shortestPathTopo =
283 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700284 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700285 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700286 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700287 if (flowPathObj == null)
288 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700289
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700290 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000291 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700292 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700293 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700294 //
295 // Use the source DPID as a heuristic to decide
296 // which controller is responsible for maintaining the
297 // shortest path.
298 // NOTE: This heuristic is error-prone: if the switch
299 // goes away and no controller is responsible for that
300 // switch, then the original Flow Path is not cleaned-up
301 //
302 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
303 if (mySwitch == null)
304 continue; // Ignore: not my responsibility
305
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700306 // Test the Data Path Summary string
307 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
308 if (dataPathSummaryStr == null)
309 continue; // Could be invalid entry?
310 if (dataPathSummaryStr.isEmpty())
311 continue; // No need to maintain this flow
312
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000313 //
314 // Test whether we need to complete the Flow cleanup,
315 // if the Flow has been deleted by the user.
316 //
317 String flowUserState = flowPathObj.getUserState();
318 if ((flowUserState != null)
319 && flowUserState.equals("FE_USER_DELETE")) {
320 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
321 boolean empty = true; // TODO: an ugly hack
322 for (IFlowEntry flowEntryObj : flowEntries) {
323 empty = false;
324 break;
325 }
326 if (empty)
327 deleteFlows.add(flowPathObj);
328 }
329
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000330 // Fetch the fields needed to recompute the shortest path
331 Short srcPortShort = flowPathObj.getSrcPort();
332 String dstDpidStr = flowPathObj.getDstSwitch();
333 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700334 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000335 if ((srcPortShort == null) ||
336 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700337 (dstPortShort == null) ||
338 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000339 continue;
340 }
341
342 Port srcPort = new Port(srcPortShort);
343 Dpid dstDpid = new Dpid(dstDpidStr);
344 Port dstPort = new Port(dstPortShort);
345 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
346 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700347 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000348
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700349 counterMyFlowPaths++;
350
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700351 //
352 // NOTE: Using here the regular getShortestPath() method
353 // won't work here, because that method calls internally
354 // "conn.endTx(Transaction.COMMIT)", and that will
355 // invalidate all handlers to the Titan database.
356 // If we want to experiment with calling here
357 // getShortestPath(), we need to refactor that code
358 // to avoid closing the transaction.
359 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700360 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000361 topoRouteService.getTopoShortestPath(shortestPathTopo,
362 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700363 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000364 if (dataPath == null) {
365 // We need the DataPath to compare the paths
366 dataPath = new DataPath();
367 dataPath.setSrcPort(srcSwitchPort);
368 dataPath.setDstPort(dstSwitchPort);
369 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700370 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000371
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700372 String newDataPathSummaryStr = dataPath.dataPathSummary();
373 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
374 continue; // Nothing changed
375
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700376 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700377 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000378
379 //
380 // Delete all leftover Flows marked for deletion from the
381 // Network MAP.
382 //
383 while (! deleteFlows.isEmpty()) {
384 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700385 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000386 }
387
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000388 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700389
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700390 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700391
392 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700393 long estimatedTime =
394 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700395 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
396 (double)estimatedTime / 1000000000 + " sec";
397 log.debug(logMsg);
398 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700399
400 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700401 double rate = 0.0;
402 if (estimatedTime > 0)
403 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700404 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700405 counterAllFlowPaths + " MyFlowPaths: " +
406 counterMyFlowPaths + " in " +
407 (double)estimatedTime / 1000000000 + " sec: " +
408 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700409 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800410 }
411 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700412
Jonathan Hart50a94982013-04-10 14:49:51 -0700413 //final ScheduledFuture<?> mapReaderHandle =
414 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800415
Jonathan Hart50a94982013-04-10 14:49:51 -0700416 //final ScheduledFuture<?> shortestPathReconcileHandle =
417 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700418
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800419 @Override
420 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700421 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700422 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800423 }
424
425 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700426 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427 }
428
429 @Override
430 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700431 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800432 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800433
434 @Override
435 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
436 Collection<Class<? extends IFloodlightService>> l =
437 new ArrayList<Class<? extends IFloodlightService>>();
438 l.add(IFlowService.class);
439 return l;
440 }
441
442 @Override
443 public Map<Class<? extends IFloodlightService>, IFloodlightService>
444 getServiceImpls() {
445 Map<Class<? extends IFloodlightService>,
446 IFloodlightService> m =
447 new HashMap<Class<? extends IFloodlightService>,
448 IFloodlightService>();
449 m.put(IFlowService.class, this);
450 return m;
451 }
452
453 @Override
454 public Collection<Class<? extends IFloodlightService>>
455 getModuleDependencies() {
456 Collection<Class<? extends IFloodlightService>> l =
457 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800458 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800459 l.add(IRestApiService.class);
460 return l;
461 }
462
463 @Override
464 public void init(FloodlightModuleContext context)
465 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700466 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800467 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800468 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800469 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
470 EnumSet.of(OFType.FLOW_MOD),
471 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700472
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800473 // TODO: An ugly hack!
474 String conf = "/tmp/cassandra.titan";
475 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700476
477 mapReaderScheduler = Executors.newScheduledThreadPool(1);
478 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800479 }
480
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700481 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000482 //
483 // Generate the next Flow Entry ID.
484 // NOTE: For now, the higher 32 bits are random, and
485 // the lower 32 bits are sequential.
486 // In the future, we need a better allocation mechanism.
487 //
488 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
489 nextFlowEntryIdPrefix = randomGenerator.nextInt();
490 nextFlowEntryIdSuffix = 0;
491 } else {
492 nextFlowEntryIdSuffix++;
493 }
494 long result = (long)nextFlowEntryIdPrefix << 32;
495 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
496 return result;
497 }
498
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800499 @Override
500 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700501 restApi.addRestletRoutable(new FlowWebRoutable());
502
503 // Initialize the Flow Entry ID generator
504 nextFlowEntryIdPrefix = randomGenerator.nextInt();
505
506 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200507 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700508 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200509 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800510 }
511
512 /**
513 * Add a flow.
514 *
515 * Internally, ONOS will automatically register the installer for
516 * receiving Flow Path Notifications for that path.
517 *
518 * @param flowPath the Flow Path to install.
519 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700520 * @param dataPathSummaryStr the data path summary string if the added
521 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800522 * @return true on success, otherwise false.
523 */
524 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700525 public boolean addFlow(FlowPath flowPath, FlowId flowId,
526 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700527 /*
528 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700529 if (flowPath.flowId().value() == measurementFlowId) {
530 modifiedMeasurementFlowTime = System.nanoTime();
531 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700532 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800533
534 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000535 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800536 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700537 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800538 != null) {
539 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
540 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000541 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800542 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700543 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800544 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
545 flowPath.flowId().toString());
546 }
547 } catch (Exception e) {
548 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700549 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000550
551 StringWriter sw = new StringWriter();
552 e.printStackTrace(new PrintWriter(sw));
553 String stacktrace = sw.toString();
554
555 log.error(":addFlow FlowId:{} failed: {}",
556 flowPath.flowId().toString(),
557 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800558 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700559 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000560 log.error(":addFlow FlowId:{} failed: Flow object not created",
561 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700562 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800563 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700564 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800565
566 //
567 // Set the Flow key:
568 // - flowId
569 //
570 flowObj.setFlowId(flowPath.flowId().toString());
571 flowObj.setType("flow");
572
573 //
574 // Set the Flow attributes:
575 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700576 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800577 // - flowPath.dataPath().srcPort()
578 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700579 // - flowPath.matchSrcMac()
580 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700581 // - flowPath.matchEthernetFrameType()
582 // - flowPath.matchVlanId()
583 // - flowPath.matchVlanPriority()
584 // - flowPath.matchSrcIPv4Net()
585 // - flowPath.matchDstIPv4Net()
586 // - flowPath.matchIpProto()
587 // - flowPath.matchIpToS()
588 // - flowPath.matchSrcTcpUdpPort()
589 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800590 //
591 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700592 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800593 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
594 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
595 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
596 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700597 if (flowPath.flowEntryMatch().matchSrcMac()) {
598 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
599 }
600 if (flowPath.flowEntryMatch().matchDstMac()) {
601 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
602 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700603 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
604 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
605 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700606 if (flowPath.flowEntryMatch().matchVlanId()) {
607 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
608 }
609 if (flowPath.flowEntryMatch().matchVlanPriority()) {
610 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
611 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700612 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
613 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
614 }
615 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
616 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
617 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700618 if (flowPath.flowEntryMatch().matchIpProto()) {
619 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700620 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700621 if (flowPath.flowEntryMatch().matchIpToS()) {
622 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
623 }
624 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
625 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
626 }
627 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
628 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700629 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800630
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700631 if (dataPathSummaryStr != null) {
632 flowObj.setDataPathSummary(dataPathSummaryStr);
633 } else {
634 flowObj.setDataPathSummary("");
635 }
636
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000637 if (found)
638 flowObj.setUserState("FE_USER_MODIFY");
639 else
640 flowObj.setUserState("FE_USER_ADD");
641
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642 // Flow edges:
643 // HeadFE
644
645
646 //
647 // Flow Entries:
648 // flowPath.dataPath().flowEntries()
649 //
650 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700651 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700652 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800653 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700654 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800655 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700656 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800657
658 //
659 // TODO: We need a proper Flow ID allocation mechanism.
660 //
661 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700662
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800663 return true;
664 }
665
666 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700667 * Add a flow entry to the Network MAP.
668 *
669 * @param flowObj the corresponding Flow Path object for the Flow Entry.
670 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700671 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700672 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700673 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700674 // Flow edges
675 // HeadFE (TODO)
676
677 //
678 // Assign the FlowEntry ID.
679 //
680 if ((flowEntry.flowEntryId() == null) ||
681 (flowEntry.flowEntryId().value() == 0)) {
682 long id = getNextFlowEntryId();
683 flowEntry.setFlowEntryId(new FlowEntryId(id));
684 }
685
686 IFlowEntry flowEntryObj = null;
687 boolean found = false;
688 try {
689 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700690 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700691 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
692 flowEntry.flowEntryId().toString());
693 found = true;
694 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700695 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700696 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
697 flowEntry.flowEntryId().toString());
698 }
699 } catch (Exception e) {
700 log.error(":addFlow FlowEntryId:{} failed",
701 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700702 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700703 }
704 if (flowEntryObj == null) {
705 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
706 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700707 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700708 }
709
710 //
711 // Set the Flow Entry key:
712 // - flowEntry.flowEntryId()
713 //
714 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
715 flowEntryObj.setType("flow_entry");
716
717 //
718 // Set the Flow Entry Edges and attributes:
719 // - Switch edge
720 // - InPort edge
721 // - OutPort edge
722 //
723 // - flowEntry.flowEntryMatch()
724 // - flowEntry.flowEntryActions()
725 // - flowEntry.dpid()
726 // - flowEntry.flowEntryUserState()
727 // - flowEntry.flowEntrySwitchState()
728 // - flowEntry.flowEntryErrorState()
729 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700730 // - flowEntry.matchSrcMac()
731 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700732 // - flowEntry.matchEthernetFrameType()
733 // - flowEntry.matchVlanId()
734 // - flowEntry.matchVlanPriority()
735 // - flowEntry.matchSrcIPv4Net()
736 // - flowEntry.matchDstIPv4Net()
737 // - flowEntry.matchIpProto()
738 // - flowEntry.matchIpToS()
739 // - flowEntry.matchSrcTcpUdpPort()
740 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700741 // - flowEntry.actionOutput()
742 //
743 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700744 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700745 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
746 flowEntryObj.setSwitch(sw);
747 if (flowEntry.flowEntryMatch().matchInPort()) {
748 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700749 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700750 flowEntry.flowEntryMatch().inPort().value());
751 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
752 flowEntryObj.setInPort(inport);
753 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700754 if (flowEntry.flowEntryMatch().matchSrcMac()) {
755 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
756 }
757 if (flowEntry.flowEntryMatch().matchDstMac()) {
758 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
759 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700760 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
761 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
762 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700763 if (flowEntry.flowEntryMatch().matchVlanId()) {
764 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
765 }
766 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
767 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
768 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700769 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
770 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
771 }
772 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
773 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
774 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700775 if (flowEntry.flowEntryMatch().matchIpProto()) {
776 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700777 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700778 if (flowEntry.flowEntryMatch().matchIpToS()) {
779 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
780 }
781 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
782 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
783 }
784 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
785 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700786 }
787
788 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
789 if (fa.actionOutput() != null) {
790 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700791 op.searchPort(flowEntry.dpid().toString(),
792 fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700793 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
794 flowEntryObj.setOutPort(outport);
795 }
796 }
797 // TODO: Hacks with hard-coded state names!
798 if (found)
799 flowEntryObj.setUserState("FE_USER_MODIFY");
800 else
801 flowEntryObj.setUserState("FE_USER_ADD");
802 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
803 //
804 // TODO: Take care of the FlowEntryErrorState.
805 //
806
807 // Flow Entries edges:
808 // Flow
809 // NextFE (TODO)
810 if (! found) {
811 flowObj.addFlowEntry(flowEntryObj);
812 flowEntryObj.setFlow(flowObj);
813 }
814
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700815 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700816 }
817
818 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000819 * Delete all previously added flows.
820 *
821 * @return true on success, otherwise false.
822 */
823 @Override
824 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000825 List<Thread> threads = new LinkedList<Thread>();
826 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
827 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000828
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000829 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700830 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000831 for (IFlowPath flowPathObj : allFlowPaths) {
832 if (flowPathObj == null)
833 continue;
834 String flowIdStr = flowPathObj.getFlowId();
835 if (flowIdStr == null)
836 continue;
837 FlowId flowId = new FlowId(flowIdStr);
838 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000839 }
840
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000841 // Delete all flows one-by-one
842 for (FlowId flowId : concurrentAllFlowIds)
843 deleteFlow(flowId);
844
845 /*
846 * TODO: A faster mechanism to delete the Flow Paths by using
847 * a number of threads. Commented-out for now.
848 */
849 /*
850 //
851 // Create the threads to delete the Flow Paths
852 //
853 for (int i = 0; i < 10; i++) {
854 Thread thread = new Thread(new Runnable() {
855 @Override
856 public void run() {
857 while (true) {
858 FlowId flowId = concurrentAllFlowIds.poll();
859 if (flowId == null)
860 return;
861 deleteFlow(flowId);
862 }
863 }}, "Delete All Flow Paths");
864 threads.add(thread);
865 }
866
867 // Start processing
868 for (Thread thread : threads) {
869 thread.start();
870 }
871
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000872 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000873 for (Thread thread : threads) {
874 try {
875 thread.join();
876 } catch (InterruptedException e) {
877 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
878 }
879 }
880 */
881
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000882 return true;
883 }
884
885 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800886 * Delete a previously added flow.
887 *
888 * @param flowId the Flow ID of the flow to delete.
889 * @return true on success, otherwise false.
890 */
891 @Override
892 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700893 /*
894 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700895 if (flowId.value() == measurementFlowId) {
896 modifiedMeasurementFlowTime = System.nanoTime();
897 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700898 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700899
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800900 IFlowPath flowObj = null;
901 //
902 // We just mark the entries for deletion,
903 // and let the switches remove each individual entry after
904 // it has been removed from the switches.
905 //
906 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700907 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800908 != null) {
909 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
910 flowId.toString());
911 } else {
912 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
913 flowId.toString());
914 }
915 } catch (Exception e) {
916 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700917 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800918 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
919 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700920 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700921 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800922 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700923 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800924
925 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000926 // Find and mark for deletion all Flow Entries,
927 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800928 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000929 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800930 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
931 boolean empty = true; // TODO: an ugly hack
932 for (IFlowEntry flowEntryObj : flowEntries) {
933 empty = false;
934 // flowObj.removeFlowEntry(flowEntryObj);
935 // conn.utils().removeFlowEntry(conn, flowEntryObj);
936 flowEntryObj.setUserState("FE_USER_DELETE");
937 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
938 }
939 // Remove from the database empty flows
940 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700941 op.removeFlowPath(flowObj);
942 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800943
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800944 return true;
945 }
946
947 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000948 * Clear the state for all previously added flows.
949 *
950 * @return true on success, otherwise false.
951 */
952 @Override
953 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000954 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000955
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000956 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700957 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000958 for (IFlowPath flowPathObj : allFlowPaths) {
959 if (flowPathObj == null)
960 continue;
961 String flowIdStr = flowPathObj.getFlowId();
962 if (flowIdStr == null)
963 continue;
964 FlowId flowId = new FlowId(flowIdStr);
965 allFlowIds.add(flowId);
966 }
967
968 // Clear all flows one-by-one
969 for (FlowId flowId : allFlowIds) {
970 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000971 }
972
973 return true;
974 }
975
976 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700977 * Clear the state for a previously added flow.
978 *
979 * @param flowId the Flow ID of the flow to clear.
980 * @return true on success, otherwise false.
981 */
982 @Override
983 public boolean clearFlow(FlowId flowId) {
984 IFlowPath flowObj = null;
985 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700986 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700987 != null) {
988 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
989 flowId.toString());
990 } else {
991 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
992 flowId.toString());
993 }
994 } catch (Exception e) {
995 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700996 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700997 log.error(":clearFlow FlowId:{} failed", flowId.toString());
998 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700999 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001000 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001001 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001002 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001003
1004 //
1005 // Remove all Flow Entries
1006 //
1007 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1008 for (IFlowEntry flowEntryObj : flowEntries) {
1009 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001010 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001011 }
1012 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001013 op.removeFlowPath(flowObj);
1014 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001015
1016 return true;
1017 }
1018
1019 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001020 * Get a previously added flow.
1021 *
1022 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001023 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001024 */
1025 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001026 public FlowPath getFlow(FlowId flowId) {
1027 IFlowPath flowObj = null;
1028 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001029 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001030 != null) {
1031 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1032 flowId.toString());
1033 } else {
1034 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1035 flowId.toString());
1036 }
1037 } catch (Exception e) {
1038 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001039 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001040 log.error(":getFlow FlowId:{} failed", flowId.toString());
1041 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001042 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001043 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001044 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001045 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001046
1047 //
1048 // Extract the Flow state
1049 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001050 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001051 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001052
1053 return flowPath;
1054 }
1055
1056 /**
1057 * Get all previously added flows by a specific installer for a given
1058 * data path endpoints.
1059 *
1060 * @param installerId the Caller ID of the installer of the flow to get.
1061 * @param dataPathEndpoints the data path endpoints of the flow to get.
1062 * @return the Flow Paths if found, otherwise null.
1063 */
1064 @Override
1065 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1066 DataPathEndpoints dataPathEndpoints) {
1067 //
1068 // TODO: The implementation below is not optimal:
1069 // We fetch all flows, and then return only the subset that match
1070 // the query conditions.
1071 // We should use the appropriate Titan/Gremlin query to filter-out
1072 // the flows as appropriate.
1073 //
1074 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001075 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001076
1077 if (allFlows == null) {
1078 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001079 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001080 }
1081
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001082 for (FlowPath flow : allFlows) {
1083 //
1084 // TODO: String-based comparison is sub-optimal.
1085 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001086 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001087 //
1088 if (! flow.installerId().toString().equals(installerId.toString()))
1089 continue;
1090 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1091 continue;
1092 }
1093 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1094 continue;
1095 }
1096 flowPaths.add(flow);
1097 }
1098
1099 if (flowPaths.isEmpty()) {
1100 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001101 } else {
1102 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1103 }
1104
1105 return flowPaths;
1106 }
1107
1108 /**
1109 * Get all installed flows by all installers for given data path endpoints.
1110 *
1111 * @param dataPathEndpoints the data path endpoints of the flows to get.
1112 * @return the Flow Paths if found, otherwise null.
1113 */
1114 @Override
1115 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1116 //
1117 // TODO: The implementation below is not optimal:
1118 // We fetch all flows, and then return only the subset that match
1119 // the query conditions.
1120 // We should use the appropriate Titan/Gremlin query to filter-out
1121 // the flows as appropriate.
1122 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001123 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1124 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001125
1126 if (allFlows == null) {
1127 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001128 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001129 }
1130
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001131 for (FlowPath flow : allFlows) {
1132 //
1133 // TODO: String-based comparison is sub-optimal.
1134 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001135 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001136 //
1137 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1138 continue;
1139 }
1140 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1141 continue;
1142 }
1143 flowPaths.add(flow);
1144 }
1145
1146 if (flowPaths.isEmpty()) {
1147 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001148 } else {
1149 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1150 }
1151
1152 return flowPaths;
1153 }
1154
1155 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001156 * Get summary of all installed flows by all installers in a given range
1157 *
1158 * @param flowId the data path endpoints of the flows to get.
1159 * @param maxFlows: the maximum number of flows to be returned
1160 * @return the Flow Paths if found, otherwise null.
1161 */
1162 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001163 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001164
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001165 // TODO: The implementation below is not optimal:
1166 // We fetch all flows, and then return only the subset that match
1167 // the query conditions.
1168 // We should use the appropriate Titan/Gremlin query to filter-out
1169 // the flows as appropriate.
1170 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001171 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001172
Jonathan Hart01f2d272013-04-04 20:03:46 -07001173 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1174
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001175 Collections.sort(flowPathsWithoutFlowEntries,
1176 new Comparator<IFlowPath>(){
1177 @Override
1178 public int compare(IFlowPath first, IFlowPath second) {
1179 // TODO Auto-generated method stub
1180 long result = new FlowId(first.getFlowId()).value()
1181 - new FlowId(second.getFlowId()).value();
1182 if (result > 0) return 1;
1183 else if (result < 0) return -1;
1184 else return 0;
1185 }
1186 }
1187 );
1188
Jonathan Hart01f2d272013-04-04 20:03:46 -07001189 return flowPathsWithoutFlowEntries;
1190
1191 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001192 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001193
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001194 if (allFlows == null) {
1195 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001196 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001197 }
1198
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001199 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001200
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001201 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001202 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001203
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001204 // start from desired flowId
1205 if (flow.flowId().value() < flowId.value()) {
1206 continue;
1207 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001208
1209 // Summarize by making null flow entry fields that are not relevant to report
1210 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1211 flowEntry.setFlowEntryActions(null);
1212 flowEntry.setFlowEntryMatch(null);
1213 }
1214
1215 flowPaths.add(flow);
1216 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1217 break;
1218 }
1219 }
1220
1221 if (flowPaths.isEmpty()) {
1222 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001223 } else {
1224 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1225 }
1226
1227 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001228 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001229 }
1230
1231 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001232 * Get all installed flows by all installers.
1233 *
1234 * @return the Flow Paths if found, otherwise null.
1235 */
1236 @Override
1237 public ArrayList<FlowPath> getAllFlows() {
1238 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001239 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001240
1241 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001242 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001243 log.debug("Get all FlowPaths: found FlowPaths");
1244 } else {
1245 log.debug("Get all FlowPaths: no FlowPaths found");
1246 }
1247 } catch (Exception e) {
1248 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001249 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001250 log.error(":getAllFlowPaths failed");
1251 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001252 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001253 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001254 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001255 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001256
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001257 for (IFlowPath flowObj : flowPathsObj) {
1258 //
1259 // Extract the Flow state
1260 //
1261 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001262 if (flowPath != null)
1263 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001264 }
1265
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001266 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001267
1268 return flowPaths;
1269 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001270
1271 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1272 Iterable<IFlowPath> flowPathsObj = null;
1273 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1274 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1275
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001276 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001277
Jonathan Hart01f2d272013-04-04 20:03:46 -07001278 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001279 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001280 log.debug("Get all FlowPaths: found FlowPaths");
1281 } else {
1282 log.debug("Get all FlowPaths: no FlowPaths found");
1283 }
1284 } catch (Exception e) {
1285 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001286 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001287 log.error(":getAllFlowPaths failed");
1288 }
1289 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1290 return new ArrayList<IFlowPath>(); // No Flows found
1291 }
1292
1293 for (IFlowPath flowObj : flowPathsObj){
1294 flowPathsObjArray.add(flowObj);
1295 }
1296 /*
1297 for (IFlowPath flowObj : flowPathsObj) {
1298 //
1299 // Extract the Flow state
1300 //
1301 FlowPath flowPath = extractFlowPath(flowObj);
1302 if (flowPath != null)
1303 flowPaths.add(flowPath);
1304 }
1305 */
1306
1307 //conn.endTx(Transaction.COMMIT);
1308
1309 return flowPathsObjArray;
1310 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001311
1312 /**
1313 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1314 *
1315 * @param flowObj the object to extract the Flow Path State from.
1316 * @return the extracted Flow Path State.
1317 */
1318 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001319 //
1320 // Extract the Flow state
1321 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001322 String flowIdStr = flowObj.getFlowId();
1323 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001324 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001325 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001326 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001327 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001328 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001329
1330 if ((flowIdStr == null) ||
1331 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001332 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001333 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001334 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001335 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001336 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001337 // TODO: A work-around, becauuse of some bogus database objects
1338 return null;
1339 }
1340
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001341 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001342 flowPath.setFlowId(new FlowId(flowIdStr));
1343 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001344 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001345 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001346 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001347 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001348 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001349 //
1350 // Extract the match conditions common for all Flow Entries
1351 //
1352 {
1353 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001354 String matchSrcMac = flowObj.getMatchSrcMac();
1355 if (matchSrcMac != null)
1356 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1357 String matchDstMac = flowObj.getMatchDstMac();
1358 if (matchDstMac != null)
1359 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001360 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1361 if (matchEthernetFrameType != null)
1362 match.enableEthernetFrameType(matchEthernetFrameType);
1363 Short matchVlanId = flowObj.getMatchVlanId();
1364 if (matchVlanId != null)
1365 match.enableVlanId(matchVlanId);
1366 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1367 if (matchVlanPriority != null)
1368 match.enableVlanPriority(matchVlanPriority);
1369 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1370 if (matchSrcIPv4Net != null)
1371 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1372 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1373 if (matchDstIPv4Net != null)
1374 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1375 Byte matchIpProto = flowObj.getMatchIpProto();
1376 if (matchIpProto != null)
1377 match.enableIpProto(matchIpProto);
1378 Byte matchIpToS = flowObj.getMatchIpToS();
1379 if (matchIpToS != null)
1380 match.enableIpToS(matchIpToS);
1381 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1382 if (matchSrcTcpUdpPort != null)
1383 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1384 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1385 if (matchDstTcpUdpPort != null)
1386 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1387
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001388 flowPath.setFlowEntryMatch(match);
1389 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001390
1391 //
1392 // Extract all Flow Entries
1393 //
1394 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1395 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001396 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1397 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001398 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001399 flowPath.dataPath().flowEntries().add(flowEntry);
1400 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001401
1402 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001403 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001404
1405 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001406 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1407 *
1408 * @param flowEntryObj the object to extract the Flow Entry State from.
1409 * @return the extracted Flow Entry State.
1410 */
1411 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1412 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1413 String switchDpidStr = flowEntryObj.getSwitchDpid();
1414 String userState = flowEntryObj.getUserState();
1415 String switchState = flowEntryObj.getSwitchState();
1416
1417 if ((flowEntryIdStr == null) ||
1418 (switchDpidStr == null) ||
1419 (userState == null) ||
1420 (switchState == null)) {
1421 // TODO: A work-around, becauuse of some bogus database objects
1422 return null;
1423 }
1424
1425 FlowEntry flowEntry = new FlowEntry();
1426 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1427 flowEntry.setDpid(new Dpid(switchDpidStr));
1428
1429 //
1430 // Extract the match conditions
1431 //
1432 FlowEntryMatch match = new FlowEntryMatch();
1433 Short matchInPort = flowEntryObj.getMatchInPort();
1434 if (matchInPort != null)
1435 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001436 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1437 if (matchSrcMac != null)
1438 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1439 String matchDstMac = flowEntryObj.getMatchDstMac();
1440 if (matchDstMac != null)
1441 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001442 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1443 if (matchEthernetFrameType != null)
1444 match.enableEthernetFrameType(matchEthernetFrameType);
1445 Short matchVlanId = flowEntryObj.getMatchVlanId();
1446 if (matchVlanId != null)
1447 match.enableVlanId(matchVlanId);
1448 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1449 if (matchVlanPriority != null)
1450 match.enableVlanPriority(matchVlanPriority);
1451 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1452 if (matchSrcIPv4Net != null)
1453 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1454 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1455 if (matchDstIPv4Net != null)
1456 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1457 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1458 if (matchIpProto != null)
1459 match.enableIpProto(matchIpProto);
1460 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1461 if (matchIpToS != null)
1462 match.enableIpToS(matchIpToS);
1463 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1464 if (matchSrcTcpUdpPort != null)
1465 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1466 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1467 if (matchDstTcpUdpPort != null)
1468 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001469 flowEntry.setFlowEntryMatch(match);
1470
1471 //
1472 // Extract the actions
1473 //
1474 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1475 Short actionOutputPort = flowEntryObj.getActionOutput();
1476 if (actionOutputPort != null) {
1477 FlowEntryAction action = new FlowEntryAction();
1478 action.setActionOutput(new Port(actionOutputPort));
1479 actions.add(action);
1480 }
1481 flowEntry.setFlowEntryActions(actions);
1482 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1483 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1484 //
1485 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1486 // and FlowEntryErrorState.
1487 //
1488 return flowEntry;
1489 }
1490
1491 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001492 * Add and maintain a shortest-path flow.
1493 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001494 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001495 *
1496 * @param flowPath the Flow Path with the endpoints and the match
1497 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001498 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001499 */
1500 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001501 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001502 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001503 // Don't do the shortest path computation here.
1504 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001505 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001506
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001507 // We need the DataPath to populate the Network MAP
1508 DataPath dataPath = new DataPath();
1509 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1510 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001511
1512 //
1513 // Prepare the computed Flow Path
1514 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001515 FlowPath computedFlowPath = new FlowPath();
1516 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1517 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001518 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001519 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001520 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001521
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001522 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001523 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001524 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001525 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001526
1527 // TODO: Mark the flow for maintenance purpose
1528
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001529 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001530 }
1531
1532 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001533 * Reconcile a flow.
1534 *
1535 * @param flowObj the flow that needs to be reconciliated.
1536 * @param newDataPath the new data path to use.
1537 * @return true on success, otherwise false.
1538 */
1539 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1540 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1541
1542 //
1543 // Set the incoming port matching and the outgoing port output
1544 // actions for each flow entry.
1545 //
1546 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1547 // Set the incoming port matching
1548 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1549 flowEntry.setFlowEntryMatch(flowEntryMatch);
1550 flowEntryMatch.enableInPort(flowEntry.inPort());
1551
1552 // Set the outgoing port output action
1553 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1554 if (flowEntryActions == null) {
1555 flowEntryActions = new ArrayList<FlowEntryAction>();
1556 flowEntry.setFlowEntryActions(flowEntryActions);
1557 }
1558 FlowEntryAction flowEntryAction = new FlowEntryAction();
1559 flowEntryAction.setActionOutput(flowEntry.outPort());
1560 flowEntryActions.add(flowEntryAction);
1561 }
1562
1563 //
1564 // Remove the old Flow Entries, and add the new Flow Entries
1565 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001566 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1567 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1568 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001569 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001570 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001571 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001572 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001573 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001574 }
1575
1576 //
1577 // Set the Data Path Summary
1578 //
1579 String dataPathSummaryStr = newDataPath.dataPathSummary();
1580 flowObj.setDataPathSummary(dataPathSummaryStr);
1581
1582 return true;
1583 }
1584
1585 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001586 * Reconcile all flows in a set.
1587 *
1588 * @param flowObjSet the set of flows that need to be reconciliated.
1589 */
1590 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1591 if (! flowObjSet.iterator().hasNext())
1592 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001593 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001594 }
1595
1596 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001597 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001598 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001599 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001600 * @param flowObj the flow path object for the flow entry to install.
1601 * @param flowEntryObj the flow entry object to install.
1602 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001603 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001604 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1605 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001606 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1607 if (flowEntryIdStr == null)
1608 return false;
1609 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001610 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001611 if (userState == null)
1612 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001613
1614 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001615 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001616 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001617 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1618 .getMessage(OFType.FLOW_MOD);
1619 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001620
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001621 short flowModCommand = OFFlowMod.OFPFC_ADD;
1622 if (userState.equals("FE_USER_ADD")) {
1623 flowModCommand = OFFlowMod.OFPFC_ADD;
1624 } else if (userState.equals("FE_USER_MODIFY")) {
1625 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1626 } else if (userState.equals("FE_USER_DELETE")) {
1627 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1628 } else {
1629 // Unknown user state. Ignore the entry
1630 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1631 flowEntryId.toString(), userState);
1632 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001633 }
1634
1635 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001636 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001637 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001638 // NOTE: The Flow matching conditions common for all Flow Entries are
1639 // used ONLY if a Flow Entry does NOT have the corresponding matching
1640 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001641 //
1642 OFMatch match = new OFMatch();
1643 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001644
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001645 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001646 Short matchInPort = flowEntryObj.getMatchInPort();
1647 if (matchInPort != null) {
1648 match.setInputPort(matchInPort);
1649 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1650 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001651
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001652 // Match the Source MAC address
1653 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1654 if (matchSrcMac == null)
1655 matchSrcMac = flowObj.getMatchSrcMac();
1656 if (matchSrcMac != null) {
1657 match.setDataLayerSource(matchSrcMac);
1658 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1659 }
1660
1661 // Match the Destination MAC address
1662 String matchDstMac = flowEntryObj.getMatchDstMac();
1663 if (matchDstMac == null)
1664 matchDstMac = flowObj.getMatchDstMac();
1665 if (matchDstMac != null) {
1666 match.setDataLayerDestination(matchDstMac);
1667 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1668 }
1669
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001670 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001671 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1672 if (matchEthernetFrameType == null)
1673 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1674 if (matchEthernetFrameType != null) {
1675 match.setDataLayerType(matchEthernetFrameType);
1676 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1677 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001678
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001679 // Match the VLAN ID
1680 Short matchVlanId = flowEntryObj.getMatchVlanId();
1681 if (matchVlanId == null)
1682 matchVlanId = flowObj.getMatchVlanId();
1683 if (matchVlanId != null) {
1684 match.setDataLayerVirtualLan(matchVlanId);
1685 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1686 }
1687
1688 // Match the VLAN priority
1689 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1690 if (matchVlanPriority == null)
1691 matchVlanPriority = flowObj.getMatchVlanPriority();
1692 if (matchVlanPriority != null) {
1693 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1694 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1695 }
1696
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001697 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001698 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1699 if (matchSrcIPv4Net == null)
1700 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1701 if (matchSrcIPv4Net != null) {
1702 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1703 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001704
1705 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001706 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1707 if (matchDstIPv4Net == null)
1708 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1709 if (matchDstIPv4Net != null) {
1710 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1711 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001712
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001713 // Match the IP protocol
1714 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1715 if (matchIpProto == null)
1716 matchIpProto = flowObj.getMatchIpProto();
1717 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001718 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001719 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001720 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001721
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001722 // Match the IP ToS (DSCP field, 6 bits)
1723 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1724 if (matchIpToS == null)
1725 matchIpToS = flowObj.getMatchIpToS();
1726 if (matchIpToS != null) {
1727 match.setNetworkTypeOfService(matchIpToS);
1728 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1729 }
1730
1731 // Match the Source TCP/UDP port
1732 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1733 if (matchSrcTcpUdpPort == null)
1734 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1735 if (matchSrcTcpUdpPort != null) {
1736 match.setTransportSource(matchSrcTcpUdpPort);
1737 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1738 }
1739
1740 // Match the Destination TCP/UDP port
1741 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1742 if (matchDstTcpUdpPort == null)
1743 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1744 if (matchDstTcpUdpPort != null) {
1745 match.setTransportDestination(matchDstTcpUdpPort);
1746 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001747 }
1748
1749 //
1750 // Fetch the actions
1751 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001752 // TODO: For now we support only the "OUTPUT" actions.
1753 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001754 List<OFAction> actions = new ArrayList<OFAction>();
1755 Short actionOutputPort = flowEntryObj.getActionOutput();
1756 if (actionOutputPort != null) {
1757 OFActionOutput action = new OFActionOutput();
1758 // XXX: The max length is hard-coded for now
1759 action.setMaxLength((short)0xffff);
1760 action.setPort(actionOutputPort);
1761 actions.add(action);
1762 }
1763
1764 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1765 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1766 .setPriority(PRIORITY_DEFAULT)
1767 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1768 .setCookie(cookie)
1769 .setCommand(flowModCommand)
1770 .setMatch(match)
1771 .setActions(actions)
1772 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1773 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1774 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1775 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1776 if (actionOutputPort != null)
1777 fm.setOutPort(actionOutputPort);
1778 }
1779
1780 //
1781 // TODO: Set the following flag
1782 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1783 // See method ForwardingBase::pushRoute()
1784 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001785
1786 //
1787 // Write the message to the switch
1788 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001789 log.debug("MEASUREMENT: Installing flow entry " + userState +
1790 " into switch DPID: " +
1791 mySwitch.getStringId() +
1792 " flowEntryId: " + flowEntryId.toString() +
1793 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1794 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1795 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001796 try {
1797 messageDamper.write(mySwitch, fm, null);
1798 mySwitch.flush();
1799 //
1800 // TODO: We should use the OpenFlow Barrier mechanism
1801 // to check for errors, and update the SwitchState
1802 // for a flow entry after the Barrier message is
1803 // is received.
1804 //
1805 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1806 } catch (IOException e) {
1807 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001808 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001809 }
1810
1811 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001812 }
1813
1814 /**
1815 * Install a Flow Entry on a switch.
1816 *
1817 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001818 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001819 * @param flowEntry the flow entry to install.
1820 * @return true on success, otherwise false.
1821 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001822 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1823 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001824 //
1825 // Create the OpenFlow Flow Modification Entry to push
1826 //
1827 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1828 .getMessage(OFType.FLOW_MOD);
1829 long cookie = flowEntry.flowEntryId().value();
1830
1831 short flowModCommand = OFFlowMod.OFPFC_ADD;
1832 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1833 flowModCommand = OFFlowMod.OFPFC_ADD;
1834 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1835 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1836 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1837 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1838 } else {
1839 // Unknown user state. Ignore the entry
1840 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1841 flowEntry.flowEntryId().toString(),
1842 flowEntry.flowEntryUserState());
1843 return false;
1844 }
1845
1846 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001847 // Fetch the match conditions.
1848 //
1849 // NOTE: The Flow matching conditions common for all Flow Entries are
1850 // used ONLY if a Flow Entry does NOT have the corresponding matching
1851 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001852 //
1853 OFMatch match = new OFMatch();
1854 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001855 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1856 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1857
1858 // Match the Incoming Port
1859 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001860 if (matchInPort != null) {
1861 match.setInputPort(matchInPort.value());
1862 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1863 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001864
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001865 // Match the Source MAC address
1866 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1867 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1868 matchSrcMac = flowPathMatch.srcMac();
1869 }
1870 if (matchSrcMac != null) {
1871 match.setDataLayerSource(matchSrcMac.toString());
1872 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1873 }
1874
1875 // Match the Destination MAC address
1876 MACAddress matchDstMac = flowEntryMatch.dstMac();
1877 if ((matchDstMac == null) && (flowPathMatch != null)) {
1878 matchDstMac = flowPathMatch.dstMac();
1879 }
1880 if (matchDstMac != null) {
1881 match.setDataLayerDestination(matchDstMac.toString());
1882 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1883 }
1884
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001885 // Match the Ethernet Frame Type
1886 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1887 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1888 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1889 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001890 if (matchEthernetFrameType != null) {
1891 match.setDataLayerType(matchEthernetFrameType);
1892 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1893 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001894
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001895 // Match the VLAN ID
1896 Short matchVlanId = flowEntryMatch.vlanId();
1897 if ((matchVlanId == null) && (flowPathMatch != null)) {
1898 matchVlanId = flowPathMatch.vlanId();
1899 }
1900 if (matchVlanId != null) {
1901 match.setDataLayerVirtualLan(matchVlanId);
1902 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1903 }
1904
1905 // Match the VLAN priority
1906 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
1907 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
1908 matchVlanPriority = flowPathMatch.vlanPriority();
1909 }
1910 if (matchVlanPriority != null) {
1911 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1912 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1913 }
1914
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001915 // Match the Source IPv4 Network prefix
1916 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1917 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1918 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1919 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001920 if (matchSrcIPv4Net != null) {
1921 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1922 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001923
1924 // Natch the Destination IPv4 Network prefix
1925 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1926 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1927 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1928 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001929 if (matchDstIPv4Net != null) {
1930 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1931 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001932
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001933 // Match the IP protocol
1934 Byte matchIpProto = flowEntryMatch.ipProto();
1935 if ((matchIpProto == null) && (flowPathMatch != null)) {
1936 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001937 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001938 if (matchIpProto != null) {
1939 match.setNetworkProtocol(matchIpProto);
1940 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001941 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001942
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001943 // Match the IP ToS (DSCP field, 6 bits)
1944 Byte matchIpToS = flowEntryMatch.ipToS();
1945 if ((matchIpToS == null) && (flowPathMatch != null)) {
1946 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001947 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001948 if (matchIpToS != null) {
1949 match.setNetworkTypeOfService(matchIpToS);
1950 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1951 }
1952
1953 // Match the Source TCP/UDP port
1954 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
1955 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
1956 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
1957 }
1958 if (matchSrcTcpUdpPort != null) {
1959 match.setTransportSource(matchSrcTcpUdpPort);
1960 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1961 }
1962
1963 // Match the Destination TCP/UDP port
1964 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
1965 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
1966 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
1967 }
1968 if (matchDstTcpUdpPort != null) {
1969 match.setTransportDestination(matchDstTcpUdpPort);
1970 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001971 }
1972
1973 //
1974 // Fetch the actions
1975 //
1976 // TODO: For now we support only the "OUTPUT" actions.
1977 //
1978 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1979 List<OFAction> actions = new ArrayList<OFAction>();
1980 ArrayList<FlowEntryAction> flowEntryActions =
1981 flowEntry.flowEntryActions();
1982 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1983 FlowEntryAction.ActionOutput actionOutput =
1984 flowEntryAction.actionOutput();
1985 if (actionOutput != null) {
1986 short actionOutputPort = actionOutput.port().value();
1987 OFActionOutput action = new OFActionOutput();
1988 // XXX: The max length is hard-coded for now
1989 action.setMaxLength((short)0xffff);
1990 action.setPort(actionOutputPort);
1991 actions.add(action);
1992 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1993 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1994 fm.setOutPort(actionOutputPort);
1995 }
1996 }
1997 }
1998
1999 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2000 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2001 .setPriority(PRIORITY_DEFAULT)
2002 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2003 .setCookie(cookie)
2004 .setCommand(flowModCommand)
2005 .setMatch(match)
2006 .setActions(actions)
2007 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
2008
2009 //
2010 // TODO: Set the following flag
2011 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2012 // See method ForwardingBase::pushRoute()
2013 //
2014
2015 //
2016 // Write the message to the switch
2017 //
2018 try {
2019 messageDamper.write(mySwitch, fm, null);
2020 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002021 //
2022 // TODO: We should use the OpenFlow Barrier mechanism
2023 // to check for errors, and update the SwitchState
2024 // for a flow entry after the Barrier message is
2025 // is received.
2026 //
2027 // TODO: The FlowEntry Object in Titan should be set
2028 // to FE_SWITCH_UPDATED.
2029 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002030 } catch (IOException e) {
2031 log.error("Failure writing flow mod from network map", e);
2032 return false;
2033 }
2034 return true;
2035 }
2036
2037 /**
2038 * Remove a Flow Entry from a switch.
2039 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002040 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002041 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002042 * @param flowEntry the flow entry to remove.
2043 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002044 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002045 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2046 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002047 //
2048 // The installFlowEntry() method implements both installation
2049 // and removal of flow entries.
2050 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002051 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002052 }
2053
2054 /**
2055 * Install a Flow Entry on a remote controller.
2056 *
2057 * TODO: We need it now: Jono
2058 * - For now it will make a REST call to the remote controller.
2059 * - Internally, it needs to know the name of the remote controller.
2060 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002061 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002062 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002063 * @return true on success, otherwise false.
2064 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002065 public boolean installRemoteFlowEntry(FlowPath flowPath,
2066 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002067 // TODO: We need it now: Jono
2068 // - For now it will make a REST call to the remote controller.
2069 // - Internally, it needs to know the name of the remote controller.
2070 return true;
2071 }
2072
2073 /**
2074 * Remove a flow entry on a remote controller.
2075 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002076 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002077 * @param flowEntry the flow entry to remove.
2078 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002079 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002080 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2081 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002082 //
2083 // The installRemoteFlowEntry() method implements both installation
2084 // and removal of flow entries.
2085 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002086 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002087 }
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002088
2089 /**
2090 * Store a path flow for measurement purpose.
2091 *
2092 * NOTE: The Flow Path argument does NOT contain flow entries.
2093 * The Shortest Path is computed, and the corresponding Flow Entries
2094 * are stored in the Flow Path.
2095 *
2096 * @param flowPath the Flow Path with the endpoints and the match
2097 * conditions to store.
2098 * @return the stored shortest-path flow on success, otherwise null.
2099 */
2100 @Override
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002101 public synchronized FlowPath measurementStorePathFlow(FlowPath flowPath) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002102 //
2103 // Prepare the Shortest Path computation if the first Flow Path
2104 //
2105 if (measurementStoredPaths.isEmpty())
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002106 measurementShortestPathTopo = topoRouteService.prepareShortestPathTopo();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002107
2108 //
2109 // Compute the Shortest Path
2110 //
2111 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002112 topoRouteService.getTopoShortestPath(measurementShortestPathTopo,
2113 flowPath.dataPath().srcPort(),
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002114 flowPath.dataPath().dstPort());
2115 if (dataPath == null) {
2116 // We need the DataPath to populate the Network MAP
2117 dataPath = new DataPath();
2118 dataPath.setSrcPort(flowPath.dataPath().srcPort());
2119 dataPath.setDstPort(flowPath.dataPath().dstPort());
2120 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07002121 dataPath.applyFlowPathFlags(flowPath.flowPathFlags());
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002122
2123 //
2124 // Set the incoming port matching and the outgoing port output
2125 // actions for each flow entry.
2126 //
2127 for (FlowEntry flowEntry : dataPath.flowEntries()) {
2128 // Set the incoming port matching
2129 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
2130 flowEntry.setFlowEntryMatch(flowEntryMatch);
2131 flowEntryMatch.enableInPort(flowEntry.inPort());
2132
2133 // Set the outgoing port output action
2134 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
2135 if (flowEntryActions == null) {
2136 flowEntryActions = new ArrayList<FlowEntryAction>();
2137 flowEntry.setFlowEntryActions(flowEntryActions);
2138 }
2139 FlowEntryAction flowEntryAction = new FlowEntryAction();
2140 flowEntryAction.setActionOutput(flowEntry.outPort());
2141 flowEntryActions.add(flowEntryAction);
2142 }
2143
2144 //
2145 // Prepare the computed Flow Path
2146 //
2147 FlowPath computedFlowPath = new FlowPath();
2148 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
2149 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07002150 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002151 computedFlowPath.setDataPath(dataPath);
2152 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
2153
2154 //
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002155 // Add the computed Flow Path to the internal storage
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002156 //
2157 measurementStoredPaths.add(computedFlowPath);
2158
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002159 log.debug("Measurement storing path {}",
2160 computedFlowPath.flowId().toString());
2161
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002162 return (computedFlowPath);
2163 }
2164
2165 /**
2166 * Install path flows for measurement purpose.
2167 *
2168 * @param numThreads the number of threads to use to install the path
2169 * flows.
2170 * @return true on success, otherwise false.
2171 */
2172 @Override
2173 public boolean measurementInstallPaths(Integer numThreads) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002174 // Create a copy of the Flow Paths to install
2175 final ConcurrentLinkedQueue<FlowPath> measurementProcessingPaths =
2176 new ConcurrentLinkedQueue<FlowPath>(measurementStoredPaths);
2177
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002178 /**
2179 * A Thread-wrapper class for executing the threads and collecting
2180 * the measurement data.
2181 */
2182 class MyThread extends Thread {
2183 public long[] execTime = new long[2000];
2184 public int samples = 0;
2185 public int threadId = -1;
2186 @Override
2187 public void run() {
2188 while (true) {
2189 FlowPath flowPath = measurementProcessingPaths.poll();
2190 if (flowPath == null)
2191 return;
2192 // Install the Flow Path
2193 FlowId flowId = new FlowId();
2194 String dataPathSummaryStr =
2195 flowPath.dataPath().dataPathSummary();
2196 long startTime = System.nanoTime();
2197 addFlow(flowPath, flowId, dataPathSummaryStr);
2198 long endTime = System.nanoTime();
2199 execTime[samples] = endTime - startTime;
2200 samples++;
2201 }
2202 }
2203 };
2204
2205 List<MyThread> threads = new LinkedList<MyThread>();
2206
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002207 log.debug("Measurement Installing {} flows",
2208 measurementProcessingPaths.size());
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002209
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002210 //
2211 // Create the threads to install the Flow Paths
2212 //
2213 for (int i = 0; i < numThreads; i++) {
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002214 MyThread thread = new MyThread();
2215 thread.threadId = i;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002216 threads.add(thread);
2217 }
2218
2219 //
2220 // Start processing
2221 //
2222 measurementEndTimeProcessingPaths = 0;
2223 measurementStartTimeProcessingPaths = System.nanoTime();
2224 for (Thread thread : threads) {
2225 thread.start();
2226 }
2227
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002228 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002229 for (Thread thread : threads) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002230 try {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002231 thread.join();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002232 } catch (InterruptedException e) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002233 log.debug("Exception waiting for a thread to install a Flow Path: ", e);
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002234 }
2235 }
2236
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002237 // Record the end of processing
2238 measurementEndTimeProcessingPaths = System.nanoTime();
2239
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002240 //
2241 // Prepare the string with measurement data per each Flow Path
2242 // installation.
2243 // The string is multiple lines: one line per Flow Path installation:
2244 // ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2245 //
2246 measurementPerFlowStr = new String();
2247 String eol = System.getProperty("line.separator");
2248 for (MyThread thread : threads) {
2249 for (int i = 0; i < thread.samples; i++) {
2250 measurementPerFlowStr += "ThreadAndTimePerFlow " + thread.threadId + " " + numThreads + " " + thread.execTime[i] + eol;
2251 }
2252 }
2253
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002254 return true;
2255 }
2256
2257 /**
2258 * Get the measurement time that took to install the path flows.
2259 *
2260 * @return the measurement time (in nanoseconds) it took to install
2261 * the path flows.
2262 */
2263 @Override
2264 public Long measurementGetInstallPathsTimeNsec() {
2265 return new Long(measurementEndTimeProcessingPaths -
2266 measurementStartTimeProcessingPaths);
2267 }
2268
2269 /**
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002270 * Get the measurement install time per Flow.
2271 *
2272 * @return a multi-line string with the following format per line:
2273 * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2274 */
2275 @Override
2276 public String measurementGetPerFlowInstallTime() {
2277 return new String(measurementPerFlowStr);
2278 }
2279
2280 /**
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002281 * Clear the path flows stored for measurement purpose.
2282 *
2283 * @return true on success, otherwise false.
2284 */
2285 @Override
2286 public boolean measurementClearAllPaths() {
2287 measurementStoredPaths.clear();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002288 topoRouteService.dropShortestPathTopo(measurementShortestPathTopo);
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002289 measurementStartTimeProcessingPaths = 0;
2290 measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002291 measurementPerFlowStr = new String();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002292
2293 return true;
2294 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002295}