blob: ebef1f45ea567da9fd237cd434355f772c1a39b3 [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;
51import net.onrc.onos.ofcontroller.util.IPv4Net;
52import net.onrc.onos.ofcontroller.util.Port;
53import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080054
55import org.openflow.protocol.OFFlowMod;
56import org.openflow.protocol.OFMatch;
57import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070058import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059import org.openflow.protocol.OFType;
60import org.openflow.protocol.action.OFAction;
61import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080062import org.slf4j.Logger;
63import org.slf4j.LoggerFactory;
64
Jonathan Hartf5315fb2013-04-05 11:41:56 -070065
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070066public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080067
Toshio Koide9fe1cb22013-06-13 13:51:11 -070068 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080069
70 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070071 protected volatile IFloodlightProviderService floodlightProvider;
72 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070073 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074
75 protected OFMessageDamper messageDamper;
76
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070077 //
78 // TODO: Values copied from elsewhere (class LearningSwitch).
79 // The local copy should go away!
80 //
81 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
82 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
83 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
84 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
85 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080086
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000087 // Flow Entry ID generation state
88 private static Random randomGenerator = new Random();
89 private static int nextFlowEntryIdPrefix = 0;
90 private static int nextFlowEntryIdSuffix = 0;
91 private static long nextFlowEntryId = 0;
92
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070093 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private static long measurementFlowId = 100000;
95 private static String measurementFlowIdStr = "0x186a0"; // 100000
96 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070097 //
98 private LinkedList<FlowPath> measurementStoredPaths = new LinkedList<FlowPath>();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070099 private long measurementStartTimeProcessingPaths = 0;
100 private long measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000101 Map<Long, ?> measurementShortestPathTopo = null;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000102 private String measurementPerFlowStr = new String();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700103
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800104 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800105 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
106
107 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700108 private ScheduledExecutorService mapReaderScheduler;
109 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700110
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700111 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800112 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700113 try {
114 runImpl();
115 } catch (Exception e) {
116 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700117 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700118 return;
119 }
120 }
121
122 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700123 long startTime = System.nanoTime();
124 int counterAllFlowEntries = 0;
125 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700126
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800127 if (floodlightProvider == null) {
128 log.debug("FloodlightProvider service not found!");
129 return;
130 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000131 Map<Long, IOFSwitch> mySwitches =
132 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700133 LinkedList<IFlowEntry> addFlowEntries =
134 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000135 LinkedList<IFlowEntry> deleteFlowEntries =
136 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700137
138 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700139 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700140 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700141 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700142 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700144 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700145 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700146 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000147
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000148 String dpidStr = flowEntryObj.getSwitchDpid();
149 if (dpidStr == null)
150 continue;
151 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800152 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000153 if (mySwitch == null)
154 continue; // Ignore the entry: not my switch
155
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700156 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700157 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700158 if (flowObj == null)
159 continue; // Should NOT happen
160 if (flowObj.getFlowId() == null)
161 continue; // Invalid entry
162
163 //
164 // NOTE: For now we process the DELETE before the ADD
165 // to cover the more common scenario.
166 // TODO: This is error prone and needs to be fixed!
167 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000168 String userState = flowEntryObj.getUserState();
169 if (userState == null)
170 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700171 if (userState.equals("FE_USER_DELETE")) {
172 // An entry that needs to be deleted.
173 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700174 installFlowEntry(mySwitch, flowObj, flowEntryObj);
175 } else {
176 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700177 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700178 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700180 // TODO: Commented-out for now
181 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700182 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700183 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700184 processed_measurement_flow = true;
185 }
186 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700187 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700188 }
189
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700190 //
191 // Process the Flow Entries that need to be added
192 //
193 for (IFlowEntry flowEntryObj : addFlowEntries) {
194 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700195 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700196 if (flowObj == null)
197 continue; // Should NOT happen
198 if (flowObj.getFlowId() == null)
199 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700201 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000203 if (mySwitch == null)
204 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700205 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800206 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000207
208 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000209 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700210 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 //
212 // TODO: We should use the OpenFlow Barrier mechanism
213 // to check for errors, and delete the Flow Entries after the
214 // Barrier message is received.
215 //
216 while (! deleteFlowEntries.isEmpty()) {
217 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
218 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700219 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000220 if (flowObj == null) {
221 log.debug("Did not find FlowPath to be deleted");
222 continue;
223 }
224 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700225 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000226 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700227
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700228 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700229
230 if (processed_measurement_flow) {
231 long estimatedTime =
232 System.nanoTime() - modifiedMeasurementFlowTime;
233 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
234 (double)estimatedTime / 1000000000 + " sec";
235 log.debug(logMsg);
236 }
237
238 long estimatedTime = System.nanoTime() - startTime;
239 double rate = 0.0;
240 if (estimatedTime > 0)
241 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
242 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
243 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
244 counterMyNotUpdatedFlowEntries + " in " +
245 (double)estimatedTime / 1000000000 + " sec: " +
246 rate + " paths/s";
247 log.debug(logMsg);
248 }
249 };
250
251 final Runnable shortestPathReconcile = new Runnable() {
252 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700253 try {
254 runImpl();
255 } catch (Exception e) {
256 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700257 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700258 return;
259 }
260 }
261
262 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700263 long startTime = System.nanoTime();
264 int counterAllFlowPaths = 0;
265 int counterMyFlowPaths = 0;
266
267 if (floodlightProvider == null) {
268 log.debug("FloodlightProvider service not found!");
269 return;
270 }
271 Map<Long, IOFSwitch> mySwitches =
272 floodlightProvider.getSwitches();
273 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
274
275 boolean processed_measurement_flow = false;
276
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700277 //
278 // Fetch and recompute the Shortest Path for those
279 // Flow Paths this controller is responsible for.
280 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000281 Map<Long, ?> shortestPathTopo =
282 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700283 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700284 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700285 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700286 if (flowPathObj == null)
287 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700288
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700289 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000290 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700292 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700293 //
294 // Use the source DPID as a heuristic to decide
295 // which controller is responsible for maintaining the
296 // shortest path.
297 // NOTE: This heuristic is error-prone: if the switch
298 // goes away and no controller is responsible for that
299 // switch, then the original Flow Path is not cleaned-up
300 //
301 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
302 if (mySwitch == null)
303 continue; // Ignore: not my responsibility
304
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700305 // Test the Data Path Summary string
306 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
307 if (dataPathSummaryStr == null)
308 continue; // Could be invalid entry?
309 if (dataPathSummaryStr.isEmpty())
310 continue; // No need to maintain this flow
311
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000312 //
313 // Test whether we need to complete the Flow cleanup,
314 // if the Flow has been deleted by the user.
315 //
316 String flowUserState = flowPathObj.getUserState();
317 if ((flowUserState != null)
318 && flowUserState.equals("FE_USER_DELETE")) {
319 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
320 boolean empty = true; // TODO: an ugly hack
321 for (IFlowEntry flowEntryObj : flowEntries) {
322 empty = false;
323 break;
324 }
325 if (empty)
326 deleteFlows.add(flowPathObj);
327 }
328
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000329 // Fetch the fields needed to recompute the shortest path
330 Short srcPortShort = flowPathObj.getSrcPort();
331 String dstDpidStr = flowPathObj.getDstSwitch();
332 Short dstPortShort = flowPathObj.getDstPort();
333 if ((srcPortShort == null) ||
334 (dstDpidStr == null) ||
335 (dstPortShort == null)) {
336 continue;
337 }
338
339 Port srcPort = new Port(srcPortShort);
340 Dpid dstDpid = new Dpid(dstDpidStr);
341 Port dstPort = new Port(dstPortShort);
342 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
343 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
344
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700345 counterMyFlowPaths++;
346
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700347 //
348 // NOTE: Using here the regular getShortestPath() method
349 // won't work here, because that method calls internally
350 // "conn.endTx(Transaction.COMMIT)", and that will
351 // invalidate all handlers to the Titan database.
352 // If we want to experiment with calling here
353 // getShortestPath(), we need to refactor that code
354 // to avoid closing the transaction.
355 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700356 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000357 topoRouteService.getTopoShortestPath(shortestPathTopo,
358 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700359 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000360 if (dataPath == null) {
361 // We need the DataPath to compare the paths
362 dataPath = new DataPath();
363 dataPath.setSrcPort(srcSwitchPort);
364 dataPath.setDstPort(dstSwitchPort);
365 }
366
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700367 String newDataPathSummaryStr = dataPath.dataPathSummary();
368 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
369 continue; // Nothing changed
370
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700371 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700372 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000373
374 //
375 // Delete all leftover Flows marked for deletion from the
376 // Network MAP.
377 //
378 while (! deleteFlows.isEmpty()) {
379 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700380 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000381 }
382
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000383 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700384
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700385 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700386
387 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700388 long estimatedTime =
389 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700390 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
391 (double)estimatedTime / 1000000000 + " sec";
392 log.debug(logMsg);
393 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700394
395 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700396 double rate = 0.0;
397 if (estimatedTime > 0)
398 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700399 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700400 counterAllFlowPaths + " MyFlowPaths: " +
401 counterMyFlowPaths + " in " +
402 (double)estimatedTime / 1000000000 + " sec: " +
403 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700404 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800405 }
406 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700407
Jonathan Hart50a94982013-04-10 14:49:51 -0700408 //final ScheduledFuture<?> mapReaderHandle =
409 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800410
Jonathan Hart50a94982013-04-10 14:49:51 -0700411 //final ScheduledFuture<?> shortestPathReconcileHandle =
412 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700413
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 @Override
415 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700416 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700417 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800418 }
419
420 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700421 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800422 }
423
424 @Override
425 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700426 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800428
429 @Override
430 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
431 Collection<Class<? extends IFloodlightService>> l =
432 new ArrayList<Class<? extends IFloodlightService>>();
433 l.add(IFlowService.class);
434 return l;
435 }
436
437 @Override
438 public Map<Class<? extends IFloodlightService>, IFloodlightService>
439 getServiceImpls() {
440 Map<Class<? extends IFloodlightService>,
441 IFloodlightService> m =
442 new HashMap<Class<? extends IFloodlightService>,
443 IFloodlightService>();
444 m.put(IFlowService.class, this);
445 return m;
446 }
447
448 @Override
449 public Collection<Class<? extends IFloodlightService>>
450 getModuleDependencies() {
451 Collection<Class<? extends IFloodlightService>> l =
452 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800453 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800454 l.add(IRestApiService.class);
455 return l;
456 }
457
458 @Override
459 public void init(FloodlightModuleContext context)
460 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700461 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800462 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
465 EnumSet.of(OFType.FLOW_MOD),
466 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700467
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800468 // TODO: An ugly hack!
469 String conf = "/tmp/cassandra.titan";
470 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700471
472 mapReaderScheduler = Executors.newScheduledThreadPool(1);
473 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800474 }
475
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700476 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000477 //
478 // Generate the next Flow Entry ID.
479 // NOTE: For now, the higher 32 bits are random, and
480 // the lower 32 bits are sequential.
481 // In the future, we need a better allocation mechanism.
482 //
483 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
484 nextFlowEntryIdPrefix = randomGenerator.nextInt();
485 nextFlowEntryIdSuffix = 0;
486 } else {
487 nextFlowEntryIdSuffix++;
488 }
489 long result = (long)nextFlowEntryIdPrefix << 32;
490 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
491 return result;
492 }
493
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800494 @Override
495 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700496 restApi.addRestletRoutable(new FlowWebRoutable());
497
498 // Initialize the Flow Entry ID generator
499 nextFlowEntryIdPrefix = randomGenerator.nextInt();
500
501 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200502 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700503 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200504 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800505 }
506
507 /**
508 * Add a flow.
509 *
510 * Internally, ONOS will automatically register the installer for
511 * receiving Flow Path Notifications for that path.
512 *
513 * @param flowPath the Flow Path to install.
514 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700515 * @param dataPathSummaryStr the data path summary string if the added
516 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800517 * @return true on success, otherwise false.
518 */
519 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700520 public boolean addFlow(FlowPath flowPath, FlowId flowId,
521 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700522 /*
523 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700524 if (flowPath.flowId().value() == measurementFlowId) {
525 modifiedMeasurementFlowTime = System.nanoTime();
526 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700527 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800528
529 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000530 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800531 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700532 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800533 != null) {
534 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
535 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000536 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800537 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700538 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800539 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
540 flowPath.flowId().toString());
541 }
542 } catch (Exception e) {
543 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700544 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000545
546 StringWriter sw = new StringWriter();
547 e.printStackTrace(new PrintWriter(sw));
548 String stacktrace = sw.toString();
549
550 log.error(":addFlow FlowId:{} failed: {}",
551 flowPath.flowId().toString(),
552 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800553 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700554 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000555 log.error(":addFlow FlowId:{} failed: Flow object not created",
556 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700557 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800558 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700559 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800560
561 //
562 // Set the Flow key:
563 // - flowId
564 //
565 flowObj.setFlowId(flowPath.flowId().toString());
566 flowObj.setType("flow");
567
568 //
569 // Set the Flow attributes:
570 // - flowPath.installerId()
571 // - flowPath.dataPath().srcPort()
572 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700573 // - flowPath.matchSrcMac()
574 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700575 // - flowPath.matchEthernetFrameType()
576 // - flowPath.matchVlanId()
577 // - flowPath.matchVlanPriority()
578 // - flowPath.matchSrcIPv4Net()
579 // - flowPath.matchDstIPv4Net()
580 // - flowPath.matchIpProto()
581 // - flowPath.matchIpToS()
582 // - flowPath.matchSrcTcpUdpPort()
583 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584 //
585 flowObj.setInstallerId(flowPath.installerId().toString());
586 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
587 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
588 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
589 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700590 if (flowPath.flowEntryMatch().matchSrcMac()) {
591 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
592 }
593 if (flowPath.flowEntryMatch().matchDstMac()) {
594 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
595 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700596 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
597 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
598 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700599 if (flowPath.flowEntryMatch().matchVlanId()) {
600 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
601 }
602 if (flowPath.flowEntryMatch().matchVlanPriority()) {
603 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
604 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700605 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
606 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
607 }
608 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
609 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
610 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700611 if (flowPath.flowEntryMatch().matchIpProto()) {
612 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700613 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700614 if (flowPath.flowEntryMatch().matchIpToS()) {
615 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
616 }
617 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
618 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
619 }
620 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
621 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700622 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800623
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700624 if (dataPathSummaryStr != null) {
625 flowObj.setDataPathSummary(dataPathSummaryStr);
626 } else {
627 flowObj.setDataPathSummary("");
628 }
629
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000630 if (found)
631 flowObj.setUserState("FE_USER_MODIFY");
632 else
633 flowObj.setUserState("FE_USER_ADD");
634
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800635 // Flow edges:
636 // HeadFE
637
638
639 //
640 // Flow Entries:
641 // flowPath.dataPath().flowEntries()
642 //
643 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700644 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700645 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800646 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700647 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800648 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700649 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800650
651 //
652 // TODO: We need a proper Flow ID allocation mechanism.
653 //
654 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700655
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800656 return true;
657 }
658
659 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700660 * Add a flow entry to the Network MAP.
661 *
662 * @param flowObj the corresponding Flow Path object for the Flow Entry.
663 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700664 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700665 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700666 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700667 // Flow edges
668 // HeadFE (TODO)
669
670 //
671 // Assign the FlowEntry ID.
672 //
673 if ((flowEntry.flowEntryId() == null) ||
674 (flowEntry.flowEntryId().value() == 0)) {
675 long id = getNextFlowEntryId();
676 flowEntry.setFlowEntryId(new FlowEntryId(id));
677 }
678
679 IFlowEntry flowEntryObj = null;
680 boolean found = false;
681 try {
682 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700683 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700684 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
685 flowEntry.flowEntryId().toString());
686 found = true;
687 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700688 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700689 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
690 flowEntry.flowEntryId().toString());
691 }
692 } catch (Exception e) {
693 log.error(":addFlow FlowEntryId:{} failed",
694 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700695 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700696 }
697 if (flowEntryObj == null) {
698 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
699 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700700 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700701 }
702
703 //
704 // Set the Flow Entry key:
705 // - flowEntry.flowEntryId()
706 //
707 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
708 flowEntryObj.setType("flow_entry");
709
710 //
711 // Set the Flow Entry Edges and attributes:
712 // - Switch edge
713 // - InPort edge
714 // - OutPort edge
715 //
716 // - flowEntry.flowEntryMatch()
717 // - flowEntry.flowEntryActions()
718 // - flowEntry.dpid()
719 // - flowEntry.flowEntryUserState()
720 // - flowEntry.flowEntrySwitchState()
721 // - flowEntry.flowEntryErrorState()
722 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700723 // - flowEntry.matchSrcMac()
724 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700725 // - flowEntry.matchEthernetFrameType()
726 // - flowEntry.matchVlanId()
727 // - flowEntry.matchVlanPriority()
728 // - flowEntry.matchSrcIPv4Net()
729 // - flowEntry.matchDstIPv4Net()
730 // - flowEntry.matchIpProto()
731 // - flowEntry.matchIpToS()
732 // - flowEntry.matchSrcTcpUdpPort()
733 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700734 // - flowEntry.actionOutput()
735 //
736 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700737 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700738 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
739 flowEntryObj.setSwitch(sw);
740 if (flowEntry.flowEntryMatch().matchInPort()) {
741 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700742 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700743 flowEntry.flowEntryMatch().inPort().value());
744 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
745 flowEntryObj.setInPort(inport);
746 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700747 if (flowEntry.flowEntryMatch().matchSrcMac()) {
748 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
749 }
750 if (flowEntry.flowEntryMatch().matchDstMac()) {
751 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
752 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700753 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
754 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
755 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700756 if (flowEntry.flowEntryMatch().matchVlanId()) {
757 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
758 }
759 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
760 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
761 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700762 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
763 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
764 }
765 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
766 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
767 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700768 if (flowEntry.flowEntryMatch().matchIpProto()) {
769 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700770 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700771 if (flowEntry.flowEntryMatch().matchIpToS()) {
772 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
773 }
774 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
775 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
776 }
777 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
778 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700779 }
780
781 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
782 if (fa.actionOutput() != null) {
783 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700784 op.searchPort(flowEntry.dpid().toString(),
785 fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700786 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
787 flowEntryObj.setOutPort(outport);
788 }
789 }
790 // TODO: Hacks with hard-coded state names!
791 if (found)
792 flowEntryObj.setUserState("FE_USER_MODIFY");
793 else
794 flowEntryObj.setUserState("FE_USER_ADD");
795 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
796 //
797 // TODO: Take care of the FlowEntryErrorState.
798 //
799
800 // Flow Entries edges:
801 // Flow
802 // NextFE (TODO)
803 if (! found) {
804 flowObj.addFlowEntry(flowEntryObj);
805 flowEntryObj.setFlow(flowObj);
806 }
807
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700808 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700809 }
810
811 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000812 * Delete all previously added flows.
813 *
814 * @return true on success, otherwise false.
815 */
816 @Override
817 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000818 List<Thread> threads = new LinkedList<Thread>();
819 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
820 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000821
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000822 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700823 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000824 for (IFlowPath flowPathObj : allFlowPaths) {
825 if (flowPathObj == null)
826 continue;
827 String flowIdStr = flowPathObj.getFlowId();
828 if (flowIdStr == null)
829 continue;
830 FlowId flowId = new FlowId(flowIdStr);
831 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000832 }
833
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000834 // Delete all flows one-by-one
835 for (FlowId flowId : concurrentAllFlowIds)
836 deleteFlow(flowId);
837
838 /*
839 * TODO: A faster mechanism to delete the Flow Paths by using
840 * a number of threads. Commented-out for now.
841 */
842 /*
843 //
844 // Create the threads to delete the Flow Paths
845 //
846 for (int i = 0; i < 10; i++) {
847 Thread thread = new Thread(new Runnable() {
848 @Override
849 public void run() {
850 while (true) {
851 FlowId flowId = concurrentAllFlowIds.poll();
852 if (flowId == null)
853 return;
854 deleteFlow(flowId);
855 }
856 }}, "Delete All Flow Paths");
857 threads.add(thread);
858 }
859
860 // Start processing
861 for (Thread thread : threads) {
862 thread.start();
863 }
864
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000865 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000866 for (Thread thread : threads) {
867 try {
868 thread.join();
869 } catch (InterruptedException e) {
870 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
871 }
872 }
873 */
874
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000875 return true;
876 }
877
878 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800879 * Delete a previously added flow.
880 *
881 * @param flowId the Flow ID of the flow to delete.
882 * @return true on success, otherwise false.
883 */
884 @Override
885 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700886 /*
887 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700888 if (flowId.value() == measurementFlowId) {
889 modifiedMeasurementFlowTime = System.nanoTime();
890 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700891 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700892
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800893 IFlowPath flowObj = null;
894 //
895 // We just mark the entries for deletion,
896 // and let the switches remove each individual entry after
897 // it has been removed from the switches.
898 //
899 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700900 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800901 != null) {
902 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
903 flowId.toString());
904 } else {
905 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
906 flowId.toString());
907 }
908 } catch (Exception e) {
909 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700910 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800911 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
912 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700913 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700914 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800915 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700916 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800917
918 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000919 // Find and mark for deletion all Flow Entries,
920 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800921 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000922 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800923 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
924 boolean empty = true; // TODO: an ugly hack
925 for (IFlowEntry flowEntryObj : flowEntries) {
926 empty = false;
927 // flowObj.removeFlowEntry(flowEntryObj);
928 // conn.utils().removeFlowEntry(conn, flowEntryObj);
929 flowEntryObj.setUserState("FE_USER_DELETE");
930 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
931 }
932 // Remove from the database empty flows
933 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700934 op.removeFlowPath(flowObj);
935 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800936
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800937 return true;
938 }
939
940 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000941 * Clear the state for all previously added flows.
942 *
943 * @return true on success, otherwise false.
944 */
945 @Override
946 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000947 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000948
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000949 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700950 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000951 for (IFlowPath flowPathObj : allFlowPaths) {
952 if (flowPathObj == null)
953 continue;
954 String flowIdStr = flowPathObj.getFlowId();
955 if (flowIdStr == null)
956 continue;
957 FlowId flowId = new FlowId(flowIdStr);
958 allFlowIds.add(flowId);
959 }
960
961 // Clear all flows one-by-one
962 for (FlowId flowId : allFlowIds) {
963 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000964 }
965
966 return true;
967 }
968
969 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700970 * Clear the state for a previously added flow.
971 *
972 * @param flowId the Flow ID of the flow to clear.
973 * @return true on success, otherwise false.
974 */
975 @Override
976 public boolean clearFlow(FlowId flowId) {
977 IFlowPath flowObj = null;
978 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700979 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700980 != null) {
981 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
982 flowId.toString());
983 } else {
984 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
985 flowId.toString());
986 }
987 } catch (Exception e) {
988 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700989 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700990 log.error(":clearFlow FlowId:{} failed", flowId.toString());
991 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700992 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700993 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700994 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700995 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700996
997 //
998 // Remove all Flow Entries
999 //
1000 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1001 for (IFlowEntry flowEntryObj : flowEntries) {
1002 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001003 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001004 }
1005 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001006 op.removeFlowPath(flowObj);
1007 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001008
1009 return true;
1010 }
1011
1012 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001013 * Get a previously added flow.
1014 *
1015 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001016 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001017 */
1018 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001019 public FlowPath getFlow(FlowId flowId) {
1020 IFlowPath flowObj = null;
1021 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001022 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001023 != null) {
1024 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1025 flowId.toString());
1026 } else {
1027 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1028 flowId.toString());
1029 }
1030 } catch (Exception e) {
1031 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001032 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001033 log.error(":getFlow FlowId:{} failed", flowId.toString());
1034 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001035 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001036 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001037 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001038 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001039
1040 //
1041 // Extract the Flow state
1042 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001043 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001044 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001045
1046 return flowPath;
1047 }
1048
1049 /**
1050 * Get all previously added flows by a specific installer for a given
1051 * data path endpoints.
1052 *
1053 * @param installerId the Caller ID of the installer of the flow to get.
1054 * @param dataPathEndpoints the data path endpoints of the flow to get.
1055 * @return the Flow Paths if found, otherwise null.
1056 */
1057 @Override
1058 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1059 DataPathEndpoints dataPathEndpoints) {
1060 //
1061 // TODO: The implementation below is not optimal:
1062 // We fetch all flows, and then return only the subset that match
1063 // the query conditions.
1064 // We should use the appropriate Titan/Gremlin query to filter-out
1065 // the flows as appropriate.
1066 //
1067 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001068 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001069
1070 if (allFlows == null) {
1071 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001072 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001073 }
1074
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001075 for (FlowPath flow : allFlows) {
1076 //
1077 // TODO: String-based comparison is sub-optimal.
1078 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001079 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001080 //
1081 if (! flow.installerId().toString().equals(installerId.toString()))
1082 continue;
1083 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1084 continue;
1085 }
1086 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1087 continue;
1088 }
1089 flowPaths.add(flow);
1090 }
1091
1092 if (flowPaths.isEmpty()) {
1093 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001094 } else {
1095 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1096 }
1097
1098 return flowPaths;
1099 }
1100
1101 /**
1102 * Get all installed flows by all installers for given data path endpoints.
1103 *
1104 * @param dataPathEndpoints the data path endpoints of the flows to get.
1105 * @return the Flow Paths if found, otherwise null.
1106 */
1107 @Override
1108 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1109 //
1110 // TODO: The implementation below is not optimal:
1111 // We fetch all flows, and then return only the subset that match
1112 // the query conditions.
1113 // We should use the appropriate Titan/Gremlin query to filter-out
1114 // the flows as appropriate.
1115 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001116 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1117 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001118
1119 if (allFlows == null) {
1120 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001121 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001122 }
1123
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001124 for (FlowPath flow : allFlows) {
1125 //
1126 // TODO: String-based comparison is sub-optimal.
1127 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001128 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001129 //
1130 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1131 continue;
1132 }
1133 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1134 continue;
1135 }
1136 flowPaths.add(flow);
1137 }
1138
1139 if (flowPaths.isEmpty()) {
1140 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001141 } else {
1142 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1143 }
1144
1145 return flowPaths;
1146 }
1147
1148 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001149 * Get summary of all installed flows by all installers in a given range
1150 *
1151 * @param flowId the data path endpoints of the flows to get.
1152 * @param maxFlows: the maximum number of flows to be returned
1153 * @return the Flow Paths if found, otherwise null.
1154 */
1155 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001156 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001157
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001158 // TODO: The implementation below is not optimal:
1159 // We fetch all flows, and then return only the subset that match
1160 // the query conditions.
1161 // We should use the appropriate Titan/Gremlin query to filter-out
1162 // the flows as appropriate.
1163 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001164 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001165
Jonathan Hart01f2d272013-04-04 20:03:46 -07001166 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1167
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001168 Collections.sort(flowPathsWithoutFlowEntries,
1169 new Comparator<IFlowPath>(){
1170 @Override
1171 public int compare(IFlowPath first, IFlowPath second) {
1172 // TODO Auto-generated method stub
1173 long result = new FlowId(first.getFlowId()).value()
1174 - new FlowId(second.getFlowId()).value();
1175 if (result > 0) return 1;
1176 else if (result < 0) return -1;
1177 else return 0;
1178 }
1179 }
1180 );
1181
Jonathan Hart01f2d272013-04-04 20:03:46 -07001182 return flowPathsWithoutFlowEntries;
1183
1184 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001185 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001186
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001187 if (allFlows == null) {
1188 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001189 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001190 }
1191
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001192 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001193
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001194 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001195 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001196
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001197 // start from desired flowId
1198 if (flow.flowId().value() < flowId.value()) {
1199 continue;
1200 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001201
1202 // Summarize by making null flow entry fields that are not relevant to report
1203 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1204 flowEntry.setFlowEntryActions(null);
1205 flowEntry.setFlowEntryMatch(null);
1206 }
1207
1208 flowPaths.add(flow);
1209 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1210 break;
1211 }
1212 }
1213
1214 if (flowPaths.isEmpty()) {
1215 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001216 } else {
1217 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1218 }
1219
1220 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001221 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001222 }
1223
1224 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001225 * Get all installed flows by all installers.
1226 *
1227 * @return the Flow Paths if found, otherwise null.
1228 */
1229 @Override
1230 public ArrayList<FlowPath> getAllFlows() {
1231 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001232 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001233
1234 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001235 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001236 log.debug("Get all FlowPaths: found FlowPaths");
1237 } else {
1238 log.debug("Get all FlowPaths: no FlowPaths found");
1239 }
1240 } catch (Exception e) {
1241 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001242 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001243 log.error(":getAllFlowPaths failed");
1244 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001245 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001246 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001247 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001248 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001249
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001250 for (IFlowPath flowObj : flowPathsObj) {
1251 //
1252 // Extract the Flow state
1253 //
1254 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001255 if (flowPath != null)
1256 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001257 }
1258
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001259 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001260
1261 return flowPaths;
1262 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001263
1264 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1265 Iterable<IFlowPath> flowPathsObj = null;
1266 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1267 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1268
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001269 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001270
Jonathan Hart01f2d272013-04-04 20:03:46 -07001271 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001272 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001273 log.debug("Get all FlowPaths: found FlowPaths");
1274 } else {
1275 log.debug("Get all FlowPaths: no FlowPaths found");
1276 }
1277 } catch (Exception e) {
1278 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001279 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001280 log.error(":getAllFlowPaths failed");
1281 }
1282 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1283 return new ArrayList<IFlowPath>(); // No Flows found
1284 }
1285
1286 for (IFlowPath flowObj : flowPathsObj){
1287 flowPathsObjArray.add(flowObj);
1288 }
1289 /*
1290 for (IFlowPath flowObj : flowPathsObj) {
1291 //
1292 // Extract the Flow state
1293 //
1294 FlowPath flowPath = extractFlowPath(flowObj);
1295 if (flowPath != null)
1296 flowPaths.add(flowPath);
1297 }
1298 */
1299
1300 //conn.endTx(Transaction.COMMIT);
1301
1302 return flowPathsObjArray;
1303 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001304
1305 /**
1306 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1307 *
1308 * @param flowObj the object to extract the Flow Path State from.
1309 * @return the extracted Flow Path State.
1310 */
1311 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001312 //
1313 // Extract the Flow state
1314 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001315 String flowIdStr = flowObj.getFlowId();
1316 String installerIdStr = flowObj.getInstallerId();
1317 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001318 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001319 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001320 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001321
1322 if ((flowIdStr == null) ||
1323 (installerIdStr == null) ||
1324 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001325 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001326 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001327 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001328 // TODO: A work-around, becauuse of some bogus database objects
1329 return null;
1330 }
1331
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001332 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001333 flowPath.setFlowId(new FlowId(flowIdStr));
1334 flowPath.setInstallerId(new CallerId(installerIdStr));
1335 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001336 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001337 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001338 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001339 //
1340 // Extract the match conditions common for all Flow Entries
1341 //
1342 {
1343 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001344 String matchSrcMac = flowObj.getMatchSrcMac();
1345 if (matchSrcMac != null)
1346 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1347 String matchDstMac = flowObj.getMatchDstMac();
1348 if (matchDstMac != null)
1349 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001350 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1351 if (matchEthernetFrameType != null)
1352 match.enableEthernetFrameType(matchEthernetFrameType);
1353 Short matchVlanId = flowObj.getMatchVlanId();
1354 if (matchVlanId != null)
1355 match.enableVlanId(matchVlanId);
1356 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1357 if (matchVlanPriority != null)
1358 match.enableVlanPriority(matchVlanPriority);
1359 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1360 if (matchSrcIPv4Net != null)
1361 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1362 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1363 if (matchDstIPv4Net != null)
1364 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1365 Byte matchIpProto = flowObj.getMatchIpProto();
1366 if (matchIpProto != null)
1367 match.enableIpProto(matchIpProto);
1368 Byte matchIpToS = flowObj.getMatchIpToS();
1369 if (matchIpToS != null)
1370 match.enableIpToS(matchIpToS);
1371 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1372 if (matchSrcTcpUdpPort != null)
1373 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1374 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1375 if (matchDstTcpUdpPort != null)
1376 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1377
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001378 flowPath.setFlowEntryMatch(match);
1379 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001380
1381 //
1382 // Extract all Flow Entries
1383 //
1384 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1385 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001386 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1387 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001388 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001389 flowPath.dataPath().flowEntries().add(flowEntry);
1390 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001391
1392 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001393 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001394
1395 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001396 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1397 *
1398 * @param flowEntryObj the object to extract the Flow Entry State from.
1399 * @return the extracted Flow Entry State.
1400 */
1401 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1402 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1403 String switchDpidStr = flowEntryObj.getSwitchDpid();
1404 String userState = flowEntryObj.getUserState();
1405 String switchState = flowEntryObj.getSwitchState();
1406
1407 if ((flowEntryIdStr == null) ||
1408 (switchDpidStr == null) ||
1409 (userState == null) ||
1410 (switchState == null)) {
1411 // TODO: A work-around, becauuse of some bogus database objects
1412 return null;
1413 }
1414
1415 FlowEntry flowEntry = new FlowEntry();
1416 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1417 flowEntry.setDpid(new Dpid(switchDpidStr));
1418
1419 //
1420 // Extract the match conditions
1421 //
1422 FlowEntryMatch match = new FlowEntryMatch();
1423 Short matchInPort = flowEntryObj.getMatchInPort();
1424 if (matchInPort != null)
1425 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001426 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1427 if (matchSrcMac != null)
1428 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1429 String matchDstMac = flowEntryObj.getMatchDstMac();
1430 if (matchDstMac != null)
1431 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001432 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1433 if (matchEthernetFrameType != null)
1434 match.enableEthernetFrameType(matchEthernetFrameType);
1435 Short matchVlanId = flowEntryObj.getMatchVlanId();
1436 if (matchVlanId != null)
1437 match.enableVlanId(matchVlanId);
1438 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1439 if (matchVlanPriority != null)
1440 match.enableVlanPriority(matchVlanPriority);
1441 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1442 if (matchSrcIPv4Net != null)
1443 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1444 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1445 if (matchDstIPv4Net != null)
1446 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1447 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1448 if (matchIpProto != null)
1449 match.enableIpProto(matchIpProto);
1450 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1451 if (matchIpToS != null)
1452 match.enableIpToS(matchIpToS);
1453 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1454 if (matchSrcTcpUdpPort != null)
1455 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1456 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1457 if (matchDstTcpUdpPort != null)
1458 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001459 flowEntry.setFlowEntryMatch(match);
1460
1461 //
1462 // Extract the actions
1463 //
1464 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1465 Short actionOutputPort = flowEntryObj.getActionOutput();
1466 if (actionOutputPort != null) {
1467 FlowEntryAction action = new FlowEntryAction();
1468 action.setActionOutput(new Port(actionOutputPort));
1469 actions.add(action);
1470 }
1471 flowEntry.setFlowEntryActions(actions);
1472 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1473 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1474 //
1475 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1476 // and FlowEntryErrorState.
1477 //
1478 return flowEntry;
1479 }
1480
1481 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001482 * Add and maintain a shortest-path flow.
1483 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001484 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001485 *
1486 * @param flowPath the Flow Path with the endpoints and the match
1487 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001488 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001489 */
1490 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001491 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001492 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001493 // Don't do the shortest path computation here.
1494 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001495 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001496
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001497 // We need the DataPath to populate the Network MAP
1498 DataPath dataPath = new DataPath();
1499 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1500 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001501
1502 //
1503 // Prepare the computed Flow Path
1504 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001505 FlowPath computedFlowPath = new FlowPath();
1506 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1507 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1508 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001509 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001510
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001511 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001512 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001513 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001514 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001515
1516 // TODO: Mark the flow for maintenance purpose
1517
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001518 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001519 }
1520
1521 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001522 * Reconcile a flow.
1523 *
1524 * @param flowObj the flow that needs to be reconciliated.
1525 * @param newDataPath the new data path to use.
1526 * @return true on success, otherwise false.
1527 */
1528 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1529 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1530
1531 //
1532 // Set the incoming port matching and the outgoing port output
1533 // actions for each flow entry.
1534 //
1535 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1536 // Set the incoming port matching
1537 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1538 flowEntry.setFlowEntryMatch(flowEntryMatch);
1539 flowEntryMatch.enableInPort(flowEntry.inPort());
1540
1541 // Set the outgoing port output action
1542 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1543 if (flowEntryActions == null) {
1544 flowEntryActions = new ArrayList<FlowEntryAction>();
1545 flowEntry.setFlowEntryActions(flowEntryActions);
1546 }
1547 FlowEntryAction flowEntryAction = new FlowEntryAction();
1548 flowEntryAction.setActionOutput(flowEntry.outPort());
1549 flowEntryActions.add(flowEntryAction);
1550 }
1551
1552 //
1553 // Remove the old Flow Entries, and add the new Flow Entries
1554 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001555 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1556 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1557 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001558 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001559 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001560 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001561 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001562 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001563 }
1564
1565 //
1566 // Set the Data Path Summary
1567 //
1568 String dataPathSummaryStr = newDataPath.dataPathSummary();
1569 flowObj.setDataPathSummary(dataPathSummaryStr);
1570
1571 return true;
1572 }
1573
1574 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001575 * Reconcile all flows in a set.
1576 *
1577 * @param flowObjSet the set of flows that need to be reconciliated.
1578 */
1579 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1580 if (! flowObjSet.iterator().hasNext())
1581 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001582 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001583 }
1584
1585 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001586 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001587 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001588 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001589 * @param flowObj the flow path object for the flow entry to install.
1590 * @param flowEntryObj the flow entry object to install.
1591 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001592 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001593 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1594 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001595 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1596 if (flowEntryIdStr == null)
1597 return false;
1598 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001599 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001600 if (userState == null)
1601 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001602
1603 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001604 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001605 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001606 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1607 .getMessage(OFType.FLOW_MOD);
1608 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001609
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001610 short flowModCommand = OFFlowMod.OFPFC_ADD;
1611 if (userState.equals("FE_USER_ADD")) {
1612 flowModCommand = OFFlowMod.OFPFC_ADD;
1613 } else if (userState.equals("FE_USER_MODIFY")) {
1614 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1615 } else if (userState.equals("FE_USER_DELETE")) {
1616 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1617 } else {
1618 // Unknown user state. Ignore the entry
1619 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1620 flowEntryId.toString(), userState);
1621 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001622 }
1623
1624 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001625 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001626 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001627 // NOTE: The Flow matching conditions common for all Flow Entries are
1628 // used ONLY if a Flow Entry does NOT have the corresponding matching
1629 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001630 //
1631 OFMatch match = new OFMatch();
1632 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001633
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001634 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001635 Short matchInPort = flowEntryObj.getMatchInPort();
1636 if (matchInPort != null) {
1637 match.setInputPort(matchInPort);
1638 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1639 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001640
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001641 // Match the Source MAC address
1642 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1643 if (matchSrcMac == null)
1644 matchSrcMac = flowObj.getMatchSrcMac();
1645 if (matchSrcMac != null) {
1646 match.setDataLayerSource(matchSrcMac);
1647 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1648 }
1649
1650 // Match the Destination MAC address
1651 String matchDstMac = flowEntryObj.getMatchDstMac();
1652 if (matchDstMac == null)
1653 matchDstMac = flowObj.getMatchDstMac();
1654 if (matchDstMac != null) {
1655 match.setDataLayerDestination(matchDstMac);
1656 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1657 }
1658
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001659 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001660 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1661 if (matchEthernetFrameType == null)
1662 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1663 if (matchEthernetFrameType != null) {
1664 match.setDataLayerType(matchEthernetFrameType);
1665 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1666 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001667
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001668 // Match the VLAN ID
1669 Short matchVlanId = flowEntryObj.getMatchVlanId();
1670 if (matchVlanId == null)
1671 matchVlanId = flowObj.getMatchVlanId();
1672 if (matchVlanId != null) {
1673 match.setDataLayerVirtualLan(matchVlanId);
1674 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1675 }
1676
1677 // Match the VLAN priority
1678 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1679 if (matchVlanPriority == null)
1680 matchVlanPriority = flowObj.getMatchVlanPriority();
1681 if (matchVlanPriority != null) {
1682 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1683 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1684 }
1685
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001686 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001687 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1688 if (matchSrcIPv4Net == null)
1689 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1690 if (matchSrcIPv4Net != null) {
1691 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1692 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001693
1694 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001695 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1696 if (matchDstIPv4Net == null)
1697 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1698 if (matchDstIPv4Net != null) {
1699 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1700 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001701
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001702 // Match the IP protocol
1703 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1704 if (matchIpProto == null)
1705 matchIpProto = flowObj.getMatchIpProto();
1706 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001707 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001708 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001709 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001710
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001711 // Match the IP ToS (DSCP field, 6 bits)
1712 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1713 if (matchIpToS == null)
1714 matchIpToS = flowObj.getMatchIpToS();
1715 if (matchIpToS != null) {
1716 match.setNetworkTypeOfService(matchIpToS);
1717 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1718 }
1719
1720 // Match the Source TCP/UDP port
1721 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1722 if (matchSrcTcpUdpPort == null)
1723 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1724 if (matchSrcTcpUdpPort != null) {
1725 match.setTransportSource(matchSrcTcpUdpPort);
1726 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1727 }
1728
1729 // Match the Destination TCP/UDP port
1730 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1731 if (matchDstTcpUdpPort == null)
1732 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1733 if (matchDstTcpUdpPort != null) {
1734 match.setTransportDestination(matchDstTcpUdpPort);
1735 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001736 }
1737
1738 //
1739 // Fetch the actions
1740 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001741 // TODO: For now we support only the "OUTPUT" actions.
1742 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001743 List<OFAction> actions = new ArrayList<OFAction>();
1744 Short actionOutputPort = flowEntryObj.getActionOutput();
1745 if (actionOutputPort != null) {
1746 OFActionOutput action = new OFActionOutput();
1747 // XXX: The max length is hard-coded for now
1748 action.setMaxLength((short)0xffff);
1749 action.setPort(actionOutputPort);
1750 actions.add(action);
1751 }
1752
1753 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1754 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1755 .setPriority(PRIORITY_DEFAULT)
1756 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1757 .setCookie(cookie)
1758 .setCommand(flowModCommand)
1759 .setMatch(match)
1760 .setActions(actions)
1761 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1762 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1763 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1764 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1765 if (actionOutputPort != null)
1766 fm.setOutPort(actionOutputPort);
1767 }
1768
1769 //
1770 // TODO: Set the following flag
1771 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1772 // See method ForwardingBase::pushRoute()
1773 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001774
1775 //
1776 // Write the message to the switch
1777 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001778 log.debug("MEASUREMENT: Installing flow entry " + userState +
1779 " into switch DPID: " +
1780 mySwitch.getStringId() +
1781 " flowEntryId: " + flowEntryId.toString() +
1782 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1783 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1784 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001785 try {
1786 messageDamper.write(mySwitch, fm, null);
1787 mySwitch.flush();
1788 //
1789 // TODO: We should use the OpenFlow Barrier mechanism
1790 // to check for errors, and update the SwitchState
1791 // for a flow entry after the Barrier message is
1792 // is received.
1793 //
1794 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1795 } catch (IOException e) {
1796 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001797 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001798 }
1799
1800 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001801 }
1802
1803 /**
1804 * Install a Flow Entry on a switch.
1805 *
1806 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001807 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001808 * @param flowEntry the flow entry to install.
1809 * @return true on success, otherwise false.
1810 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001811 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1812 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001813 //
1814 // Create the OpenFlow Flow Modification Entry to push
1815 //
1816 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1817 .getMessage(OFType.FLOW_MOD);
1818 long cookie = flowEntry.flowEntryId().value();
1819
1820 short flowModCommand = OFFlowMod.OFPFC_ADD;
1821 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1822 flowModCommand = OFFlowMod.OFPFC_ADD;
1823 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1824 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1825 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1826 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1827 } else {
1828 // Unknown user state. Ignore the entry
1829 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1830 flowEntry.flowEntryId().toString(),
1831 flowEntry.flowEntryUserState());
1832 return false;
1833 }
1834
1835 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001836 // Fetch the match conditions.
1837 //
1838 // NOTE: The Flow matching conditions common for all Flow Entries are
1839 // used ONLY if a Flow Entry does NOT have the corresponding matching
1840 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001841 //
1842 OFMatch match = new OFMatch();
1843 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001844 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1845 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1846
1847 // Match the Incoming Port
1848 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001849 if (matchInPort != null) {
1850 match.setInputPort(matchInPort.value());
1851 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1852 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001853
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001854 // Match the Source MAC address
1855 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1856 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1857 matchSrcMac = flowPathMatch.srcMac();
1858 }
1859 if (matchSrcMac != null) {
1860 match.setDataLayerSource(matchSrcMac.toString());
1861 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1862 }
1863
1864 // Match the Destination MAC address
1865 MACAddress matchDstMac = flowEntryMatch.dstMac();
1866 if ((matchDstMac == null) && (flowPathMatch != null)) {
1867 matchDstMac = flowPathMatch.dstMac();
1868 }
1869 if (matchDstMac != null) {
1870 match.setDataLayerDestination(matchDstMac.toString());
1871 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1872 }
1873
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001874 // Match the Ethernet Frame Type
1875 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1876 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1877 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1878 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001879 if (matchEthernetFrameType != null) {
1880 match.setDataLayerType(matchEthernetFrameType);
1881 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1882 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001883
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001884 // Match the VLAN ID
1885 Short matchVlanId = flowEntryMatch.vlanId();
1886 if ((matchVlanId == null) && (flowPathMatch != null)) {
1887 matchVlanId = flowPathMatch.vlanId();
1888 }
1889 if (matchVlanId != null) {
1890 match.setDataLayerVirtualLan(matchVlanId);
1891 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1892 }
1893
1894 // Match the VLAN priority
1895 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
1896 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
1897 matchVlanPriority = flowPathMatch.vlanPriority();
1898 }
1899 if (matchVlanPriority != null) {
1900 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1901 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1902 }
1903
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001904 // Match the Source IPv4 Network prefix
1905 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1906 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1907 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1908 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001909 if (matchSrcIPv4Net != null) {
1910 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1911 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001912
1913 // Natch the Destination IPv4 Network prefix
1914 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1915 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1916 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1917 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001918 if (matchDstIPv4Net != null) {
1919 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1920 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001921
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001922 // Match the IP protocol
1923 Byte matchIpProto = flowEntryMatch.ipProto();
1924 if ((matchIpProto == null) && (flowPathMatch != null)) {
1925 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001926 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001927 if (matchIpProto != null) {
1928 match.setNetworkProtocol(matchIpProto);
1929 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001930 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001931
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001932 // Match the IP ToS (DSCP field, 6 bits)
1933 Byte matchIpToS = flowEntryMatch.ipToS();
1934 if ((matchIpToS == null) && (flowPathMatch != null)) {
1935 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001936 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001937 if (matchIpToS != null) {
1938 match.setNetworkTypeOfService(matchIpToS);
1939 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1940 }
1941
1942 // Match the Source TCP/UDP port
1943 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
1944 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
1945 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
1946 }
1947 if (matchSrcTcpUdpPort != null) {
1948 match.setTransportSource(matchSrcTcpUdpPort);
1949 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1950 }
1951
1952 // Match the Destination TCP/UDP port
1953 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
1954 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
1955 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
1956 }
1957 if (matchDstTcpUdpPort != null) {
1958 match.setTransportDestination(matchDstTcpUdpPort);
1959 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001960 }
1961
1962 //
1963 // Fetch the actions
1964 //
1965 // TODO: For now we support only the "OUTPUT" actions.
1966 //
1967 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1968 List<OFAction> actions = new ArrayList<OFAction>();
1969 ArrayList<FlowEntryAction> flowEntryActions =
1970 flowEntry.flowEntryActions();
1971 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1972 FlowEntryAction.ActionOutput actionOutput =
1973 flowEntryAction.actionOutput();
1974 if (actionOutput != null) {
1975 short actionOutputPort = actionOutput.port().value();
1976 OFActionOutput action = new OFActionOutput();
1977 // XXX: The max length is hard-coded for now
1978 action.setMaxLength((short)0xffff);
1979 action.setPort(actionOutputPort);
1980 actions.add(action);
1981 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1982 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1983 fm.setOutPort(actionOutputPort);
1984 }
1985 }
1986 }
1987
1988 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1989 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1990 .setPriority(PRIORITY_DEFAULT)
1991 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1992 .setCookie(cookie)
1993 .setCommand(flowModCommand)
1994 .setMatch(match)
1995 .setActions(actions)
1996 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1997
1998 //
1999 // TODO: Set the following flag
2000 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2001 // See method ForwardingBase::pushRoute()
2002 //
2003
2004 //
2005 // Write the message to the switch
2006 //
2007 try {
2008 messageDamper.write(mySwitch, fm, null);
2009 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002010 //
2011 // TODO: We should use the OpenFlow Barrier mechanism
2012 // to check for errors, and update the SwitchState
2013 // for a flow entry after the Barrier message is
2014 // is received.
2015 //
2016 // TODO: The FlowEntry Object in Titan should be set
2017 // to FE_SWITCH_UPDATED.
2018 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002019 } catch (IOException e) {
2020 log.error("Failure writing flow mod from network map", e);
2021 return false;
2022 }
2023 return true;
2024 }
2025
2026 /**
2027 * Remove a Flow Entry from a switch.
2028 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002029 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002030 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002031 * @param flowEntry the flow entry to remove.
2032 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002033 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002034 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2035 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002036 //
2037 // The installFlowEntry() method implements both installation
2038 // and removal of flow entries.
2039 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002040 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002041 }
2042
2043 /**
2044 * Install a Flow Entry on a remote controller.
2045 *
2046 * TODO: We need it now: Jono
2047 * - For now it will make a REST call to the remote controller.
2048 * - Internally, it needs to know the name of the remote controller.
2049 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002050 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002051 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002052 * @return true on success, otherwise false.
2053 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002054 public boolean installRemoteFlowEntry(FlowPath flowPath,
2055 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002056 // TODO: We need it now: Jono
2057 // - For now it will make a REST call to the remote controller.
2058 // - Internally, it needs to know the name of the remote controller.
2059 return true;
2060 }
2061
2062 /**
2063 * Remove a flow entry on a remote controller.
2064 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002065 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002066 * @param flowEntry the flow entry to remove.
2067 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002068 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002069 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2070 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002071 //
2072 // The installRemoteFlowEntry() method implements both installation
2073 // and removal of flow entries.
2074 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002075 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002076 }
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002077
2078 /**
2079 * Store a path flow for measurement purpose.
2080 *
2081 * NOTE: The Flow Path argument does NOT contain flow entries.
2082 * The Shortest Path is computed, and the corresponding Flow Entries
2083 * are stored in the Flow Path.
2084 *
2085 * @param flowPath the Flow Path with the endpoints and the match
2086 * conditions to store.
2087 * @return the stored shortest-path flow on success, otherwise null.
2088 */
2089 @Override
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002090 public synchronized FlowPath measurementStorePathFlow(FlowPath flowPath) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002091 //
2092 // Prepare the Shortest Path computation if the first Flow Path
2093 //
2094 if (measurementStoredPaths.isEmpty())
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002095 measurementShortestPathTopo = topoRouteService.prepareShortestPathTopo();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002096
2097 //
2098 // Compute the Shortest Path
2099 //
2100 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002101 topoRouteService.getTopoShortestPath(measurementShortestPathTopo,
2102 flowPath.dataPath().srcPort(),
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002103 flowPath.dataPath().dstPort());
2104 if (dataPath == null) {
2105 // We need the DataPath to populate the Network MAP
2106 dataPath = new DataPath();
2107 dataPath.setSrcPort(flowPath.dataPath().srcPort());
2108 dataPath.setDstPort(flowPath.dataPath().dstPort());
2109 }
2110
2111 //
2112 // Set the incoming port matching and the outgoing port output
2113 // actions for each flow entry.
2114 //
2115 for (FlowEntry flowEntry : dataPath.flowEntries()) {
2116 // Set the incoming port matching
2117 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
2118 flowEntry.setFlowEntryMatch(flowEntryMatch);
2119 flowEntryMatch.enableInPort(flowEntry.inPort());
2120
2121 // Set the outgoing port output action
2122 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
2123 if (flowEntryActions == null) {
2124 flowEntryActions = new ArrayList<FlowEntryAction>();
2125 flowEntry.setFlowEntryActions(flowEntryActions);
2126 }
2127 FlowEntryAction flowEntryAction = new FlowEntryAction();
2128 flowEntryAction.setActionOutput(flowEntry.outPort());
2129 flowEntryActions.add(flowEntryAction);
2130 }
2131
2132 //
2133 // Prepare the computed Flow Path
2134 //
2135 FlowPath computedFlowPath = new FlowPath();
2136 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
2137 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
2138 computedFlowPath.setDataPath(dataPath);
2139 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
2140
2141 //
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002142 // Add the computed Flow Path to the internal storage
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002143 //
2144 measurementStoredPaths.add(computedFlowPath);
2145
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002146 log.debug("Measurement storing path {}",
2147 computedFlowPath.flowId().toString());
2148
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002149 return (computedFlowPath);
2150 }
2151
2152 /**
2153 * Install path flows for measurement purpose.
2154 *
2155 * @param numThreads the number of threads to use to install the path
2156 * flows.
2157 * @return true on success, otherwise false.
2158 */
2159 @Override
2160 public boolean measurementInstallPaths(Integer numThreads) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002161 // Create a copy of the Flow Paths to install
2162 final ConcurrentLinkedQueue<FlowPath> measurementProcessingPaths =
2163 new ConcurrentLinkedQueue<FlowPath>(measurementStoredPaths);
2164
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002165 /**
2166 * A Thread-wrapper class for executing the threads and collecting
2167 * the measurement data.
2168 */
2169 class MyThread extends Thread {
2170 public long[] execTime = new long[2000];
2171 public int samples = 0;
2172 public int threadId = -1;
2173 @Override
2174 public void run() {
2175 while (true) {
2176 FlowPath flowPath = measurementProcessingPaths.poll();
2177 if (flowPath == null)
2178 return;
2179 // Install the Flow Path
2180 FlowId flowId = new FlowId();
2181 String dataPathSummaryStr =
2182 flowPath.dataPath().dataPathSummary();
2183 long startTime = System.nanoTime();
2184 addFlow(flowPath, flowId, dataPathSummaryStr);
2185 long endTime = System.nanoTime();
2186 execTime[samples] = endTime - startTime;
2187 samples++;
2188 }
2189 }
2190 };
2191
2192 List<MyThread> threads = new LinkedList<MyThread>();
2193
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002194 log.debug("Measurement Installing {} flows",
2195 measurementProcessingPaths.size());
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002196
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002197 //
2198 // Create the threads to install the Flow Paths
2199 //
2200 for (int i = 0; i < numThreads; i++) {
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002201 MyThread thread = new MyThread();
2202 thread.threadId = i;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002203 threads.add(thread);
2204 }
2205
2206 //
2207 // Start processing
2208 //
2209 measurementEndTimeProcessingPaths = 0;
2210 measurementStartTimeProcessingPaths = System.nanoTime();
2211 for (Thread thread : threads) {
2212 thread.start();
2213 }
2214
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002215 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002216 for (Thread thread : threads) {
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002217 try {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002218 thread.join();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002219 } catch (InterruptedException e) {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002220 log.debug("Exception waiting for a thread to install a Flow Path: ", e);
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002221 }
2222 }
2223
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00002224 // Record the end of processing
2225 measurementEndTimeProcessingPaths = System.nanoTime();
2226
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002227 //
2228 // Prepare the string with measurement data per each Flow Path
2229 // installation.
2230 // The string is multiple lines: one line per Flow Path installation:
2231 // ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2232 //
2233 measurementPerFlowStr = new String();
2234 String eol = System.getProperty("line.separator");
2235 for (MyThread thread : threads) {
2236 for (int i = 0; i < thread.samples; i++) {
2237 measurementPerFlowStr += "ThreadAndTimePerFlow " + thread.threadId + " " + numThreads + " " + thread.execTime[i] + eol;
2238 }
2239 }
2240
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002241 return true;
2242 }
2243
2244 /**
2245 * Get the measurement time that took to install the path flows.
2246 *
2247 * @return the measurement time (in nanoseconds) it took to install
2248 * the path flows.
2249 */
2250 @Override
2251 public Long measurementGetInstallPathsTimeNsec() {
2252 return new Long(measurementEndTimeProcessingPaths -
2253 measurementStartTimeProcessingPaths);
2254 }
2255
2256 /**
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002257 * Get the measurement install time per Flow.
2258 *
2259 * @return a multi-line string with the following format per line:
2260 * ThreadAndTimePerFlow <ThreadId> <TotalThreads> <Time(ns)>
2261 */
2262 @Override
2263 public String measurementGetPerFlowInstallTime() {
2264 return new String(measurementPerFlowStr);
2265 }
2266
2267 /**
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002268 * Clear the path flows stored for measurement purpose.
2269 *
2270 * @return true on success, otherwise false.
2271 */
2272 @Override
2273 public boolean measurementClearAllPaths() {
2274 measurementStoredPaths.clear();
Pavlin Radoslavov9556b142013-05-20 21:49:04 +00002275 topoRouteService.dropShortestPathTopo(measurementShortestPathTopo);
Pavlin Radoslavove0938f32013-05-07 23:17:22 +00002276 measurementStartTimeProcessingPaths = 0;
2277 measurementEndTimeProcessingPaths = 0;
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +00002278 measurementPerFlowStr = new String();
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -07002279
2280 return true;
2281 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002282}