blob: c39b816ca458f06c7aca1873a1bcea3edb6f956f [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;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070036import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070037import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070038import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070039import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070040import net.onrc.onos.ofcontroller.util.CallerId;
41import net.onrc.onos.ofcontroller.util.DataPath;
42import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
43import net.onrc.onos.ofcontroller.util.Dpid;
44import net.onrc.onos.ofcontroller.util.FlowEntry;
45import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070046import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
47import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070048import net.onrc.onos.ofcontroller.util.FlowEntryId;
49import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
50import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
51import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
52import net.onrc.onos.ofcontroller.util.FlowId;
53import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070054import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070055import net.onrc.onos.ofcontroller.util.IPv4Net;
56import net.onrc.onos.ofcontroller.util.Port;
57import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080058
59import org.openflow.protocol.OFFlowMod;
60import org.openflow.protocol.OFMatch;
61import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070062import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080063import org.openflow.protocol.OFType;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070064import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080065import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
admin944ef4f2013-10-08 17:48:37 -070068/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070069 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070070 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070071public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072
Toshio Koide9fe1cb22013-06-13 13:51:11 -070073 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080074
75 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070076 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070077 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070078 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080079
80 protected OFMessageDamper messageDamper;
81
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070082 //
83 // TODO: Values copied from elsewhere (class LearningSwitch).
84 // The local copy should go away!
85 //
86 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
87 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
88 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
89 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
90 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080091
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000092 // Flow Entry ID generation state
93 private static Random randomGenerator = new Random();
94 private static int nextFlowEntryIdPrefix = 0;
95 private static int nextFlowEntryIdSuffix = 0;
96 private static long nextFlowEntryId = 0;
97
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070098 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070099 private static long measurementFlowId = 100000;
100 private static String measurementFlowIdStr = "0x186a0"; // 100000
101 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700102 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700103
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800104 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800105 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
106
107 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700108 private ScheduledExecutorService mapReaderScheduler;
109 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700110
admin944ef4f2013-10-08 17:48:37 -0700111 /**
112 * Periodic task for reading the Flow Entries and pushing changes
113 * into the switches.
114 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700115 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800116 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700117 try {
118 runImpl();
119 } catch (Exception e) {
120 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700121 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700122 return;
123 }
124 }
125
126 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700127 long startTime = System.nanoTime();
128 int counterAllFlowEntries = 0;
129 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700130
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800131 if (floodlightProvider == null) {
132 log.debug("FloodlightProvider service not found!");
133 return;
134 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000135 Map<Long, IOFSwitch> mySwitches =
136 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700137 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700138 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700139 return;
140 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700141 LinkedList<IFlowEntry> addFlowEntries =
142 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143 LinkedList<IFlowEntry> deleteFlowEntries =
144 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700145
146 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700147 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700148 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700149 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700150 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000151 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700152 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700153 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700154 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000155
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000156 String dpidStr = flowEntryObj.getSwitchDpid();
157 if (dpidStr == null)
158 continue;
159 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800160 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000161 if (mySwitch == null)
162 continue; // Ignore the entry: not my switch
163
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700164 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700165 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 if (flowObj == null)
167 continue; // Should NOT happen
168 if (flowObj.getFlowId() == null)
169 continue; // Invalid entry
170
171 //
172 // NOTE: For now we process the DELETE before the ADD
173 // to cover the more common scenario.
174 // TODO: This is error prone and needs to be fixed!
175 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000176 String userState = flowEntryObj.getUserState();
177 if (userState == null)
178 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700179 if (userState.equals("FE_USER_DELETE")) {
180 // An entry that needs to be deleted.
181 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700182 installFlowEntry(mySwitch, flowObj, flowEntryObj);
183 } else {
184 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700185 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700186 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700187 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700188 // TODO: Commented-out for now
189 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700190 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700191 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700192 processed_measurement_flow = true;
193 }
194 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700195 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700196 }
197
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700198 //
199 // Process the Flow Entries that need to be added
200 //
201 for (IFlowEntry flowEntryObj : addFlowEntries) {
202 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700203 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700204 if (flowObj == null)
205 continue; // Should NOT happen
206 if (flowObj.getFlowId() == null)
207 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700208
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700209 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700210 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 if (mySwitch == null)
212 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700213 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800214 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000215
216 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000217 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700218 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219 //
220 // TODO: We should use the OpenFlow Barrier mechanism
221 // to check for errors, and delete the Flow Entries after the
222 // Barrier message is received.
223 //
224 while (! deleteFlowEntries.isEmpty()) {
225 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
226 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700227 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000228 if (flowObj == null) {
229 log.debug("Did not find FlowPath to be deleted");
230 continue;
231 }
232 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700233 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000234 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700235
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700236 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700237
238 if (processed_measurement_flow) {
239 long estimatedTime =
240 System.nanoTime() - modifiedMeasurementFlowTime;
241 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
242 (double)estimatedTime / 1000000000 + " sec";
243 log.debug(logMsg);
244 }
245
246 long estimatedTime = System.nanoTime() - startTime;
247 double rate = 0.0;
248 if (estimatedTime > 0)
249 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
250 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
251 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
252 counterMyNotUpdatedFlowEntries + " in " +
253 (double)estimatedTime / 1000000000 + " sec: " +
254 rate + " paths/s";
255 log.debug(logMsg);
256 }
257 };
258
admin944ef4f2013-10-08 17:48:37 -0700259 /**
260 * Periodic task for reading the Flow Paths and recomputing the
261 * shortest paths.
262 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700263 final Runnable shortestPathReconcile = new Runnable() {
264 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700265 try {
266 runImpl();
267 } catch (Exception e) {
268 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700269 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700270 return;
271 }
272 }
273
274 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700275 long startTime = System.nanoTime();
276 int counterAllFlowPaths = 0;
277 int counterMyFlowPaths = 0;
278
279 if (floodlightProvider == null) {
280 log.debug("FloodlightProvider service not found!");
281 return;
282 }
283 Map<Long, IOFSwitch> mySwitches =
284 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700285 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700286 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700287 return;
288 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700289 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
290
291 boolean processed_measurement_flow = false;
292
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700293 //
294 // Fetch and recompute the Shortest Path for those
295 // Flow Paths this controller is responsible for.
296 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000297 Map<Long, ?> shortestPathTopo =
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700298 topologyNetService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700299 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700300 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700301 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700302 if (flowPathObj == null)
303 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700304
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700305 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000306 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700308 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700309 //
310 // Use the source DPID as a heuristic to decide
311 // which controller is responsible for maintaining the
312 // shortest path.
313 // NOTE: This heuristic is error-prone: if the switch
314 // goes away and no controller is responsible for that
315 // switch, then the original Flow Path is not cleaned-up
316 //
317 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
318 if (mySwitch == null)
319 continue; // Ignore: not my responsibility
320
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700321 // Test the Data Path Summary string
322 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
323 if (dataPathSummaryStr == null)
324 continue; // Could be invalid entry?
325 if (dataPathSummaryStr.isEmpty())
326 continue; // No need to maintain this flow
327
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000328 //
329 // Test whether we need to complete the Flow cleanup,
330 // if the Flow has been deleted by the user.
331 //
332 String flowUserState = flowPathObj.getUserState();
333 if ((flowUserState != null)
334 && flowUserState.equals("FE_USER_DELETE")) {
335 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700336 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000337 if (empty)
338 deleteFlows.add(flowPathObj);
339 }
340
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000341 // Fetch the fields needed to recompute the shortest path
342 Short srcPortShort = flowPathObj.getSrcPort();
343 String dstDpidStr = flowPathObj.getDstSwitch();
344 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700345 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000346 if ((srcPortShort == null) ||
347 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700348 (dstPortShort == null) ||
349 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000350 continue;
351 }
352
353 Port srcPort = new Port(srcPortShort);
354 Dpid dstDpid = new Dpid(dstDpidStr);
355 Port dstPort = new Port(dstPortShort);
356 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
357 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700358 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000359
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700360 counterMyFlowPaths++;
361
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700362 //
363 // NOTE: Using here the regular getShortestPath() method
364 // won't work here, because that method calls internally
365 // "conn.endTx(Transaction.COMMIT)", and that will
366 // invalidate all handlers to the Titan database.
367 // If we want to experiment with calling here
368 // getShortestPath(), we need to refactor that code
369 // to avoid closing the transaction.
370 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700371 DataPath dataPath =
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700372 topologyNetService.getTopoShortestPath(shortestPathTopo,
373 srcSwitchPort,
374 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000375 if (dataPath == null) {
376 // We need the DataPath to compare the paths
377 dataPath = new DataPath();
378 dataPath.setSrcPort(srcSwitchPort);
379 dataPath.setDstPort(dstSwitchPort);
380 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700381 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000382
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700383 String newDataPathSummaryStr = dataPath.dataPathSummary();
384 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
385 continue; // Nothing changed
386
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700387 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700388 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000389
390 //
391 // Delete all leftover Flows marked for deletion from the
392 // Network MAP.
393 //
394 while (! deleteFlows.isEmpty()) {
395 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700396 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000397 }
398
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700399 topologyNetService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700400
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700401 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700402
403 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700404 long estimatedTime =
405 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700406 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
407 (double)estimatedTime / 1000000000 + " sec";
408 log.debug(logMsg);
409 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700410
411 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700412 double rate = 0.0;
413 if (estimatedTime > 0)
414 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700415 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700416 counterAllFlowPaths + " MyFlowPaths: " +
417 counterMyFlowPaths + " in " +
418 (double)estimatedTime / 1000000000 + " sec: " +
419 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700420 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800421 }
422 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700423
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800424
admin944ef4f2013-10-08 17:48:37 -0700425 /**
426 * Initialize the Flow Manager.
427 *
428 * @param conf the Graph Database configuration string.
429 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800430 @Override
431 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700432 op = new GraphDBOperation(conf);
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700433 topologyNetService = new TopologyManager(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800434 }
435
admin944ef4f2013-10-08 17:48:37 -0700436 /**
437 * Shutdown the Flow Manager operation.
438 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700440 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800441 }
442
admin944ef4f2013-10-08 17:48:37 -0700443 /**
444 * Shutdown the Flow Manager operation.
445 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800446 @Override
447 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700448 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800449 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800450
admin944ef4f2013-10-08 17:48:37 -0700451 /**
452 * Get the collection of offered module services.
453 *
454 * @return the collection of offered module services.
455 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800456 @Override
457 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
458 Collection<Class<? extends IFloodlightService>> l =
459 new ArrayList<Class<? extends IFloodlightService>>();
460 l.add(IFlowService.class);
461 return l;
462 }
463
admin944ef4f2013-10-08 17:48:37 -0700464 /**
465 * Get the collection of implemented services.
466 *
467 * @return the collection of implemented services.
468 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800469 @Override
470 public Map<Class<? extends IFloodlightService>, IFloodlightService>
471 getServiceImpls() {
472 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700473 IFloodlightService> m =
474 new HashMap<Class<? extends IFloodlightService>,
475 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800476 m.put(IFlowService.class, this);
477 return m;
478 }
479
admin944ef4f2013-10-08 17:48:37 -0700480 /**
481 * Get the collection of modules this module depends on.
482 *
483 * @return the collection of modules this module depends on.
484 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800485 @Override
486 public Collection<Class<? extends IFloodlightService>>
487 getModuleDependencies() {
488 Collection<Class<? extends IFloodlightService>> l =
489 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800490 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700491 l.add(INetworkGraphService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800492 l.add(IRestApiService.class);
493 return l;
494 }
495
admin944ef4f2013-10-08 17:48:37 -0700496 /**
497 * Initialize the module.
498 *
499 * @param context the module context to use for the initialization.
500 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800501 @Override
502 public void init(FloodlightModuleContext context)
503 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700504 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800505 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800506 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800507 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
508 EnumSet.of(OFType.FLOW_MOD),
509 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700510
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700511 String conf = "";
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800512 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700513
admin944ef4f2013-10-08 17:48:37 -0700514 mapReaderScheduler = Executors.newScheduledThreadPool(1);
515 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800516 }
517
admin944ef4f2013-10-08 17:48:37 -0700518 /**
519 * Get the next Flow Entry ID to use.
520 *
521 * @return the next Flow Entry ID to use.
522 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700523 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000524 //
525 // Generate the next Flow Entry ID.
526 // NOTE: For now, the higher 32 bits are random, and
527 // the lower 32 bits are sequential.
528 // In the future, we need a better allocation mechanism.
529 //
530 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
531 nextFlowEntryIdPrefix = randomGenerator.nextInt();
532 nextFlowEntryIdSuffix = 0;
533 } else {
534 nextFlowEntryIdSuffix++;
535 }
536 long result = (long)nextFlowEntryIdPrefix << 32;
537 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
538 return result;
539 }
540
admin944ef4f2013-10-08 17:48:37 -0700541 /**
542 * Startup module operation.
543 *
544 * @param context the module context to use for the startup.
545 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800546 @Override
547 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700548 restApi.addRestletRoutable(new FlowWebRoutable());
Jonathan Hart50a94982013-04-10 14:49:51 -0700549
admin944ef4f2013-10-08 17:48:37 -0700550 // Initialize the Flow Entry ID generator
551 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Jonathan Hart50a94982013-04-10 14:49:51 -0700552
admin944ef4f2013-10-08 17:48:37 -0700553 mapReaderScheduler.scheduleAtFixedRate(
554 mapReader, 3, 3, TimeUnit.SECONDS);
555 shortestPathReconcileScheduler.scheduleAtFixedRate(
556 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800557 }
558
559 /**
560 * Add a flow.
561 *
562 * Internally, ONOS will automatically register the installer for
563 * receiving Flow Path Notifications for that path.
564 *
565 * @param flowPath the Flow Path to install.
566 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700567 * @param dataPathSummaryStr the data path summary string if the added
568 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800569 * @return true on success, otherwise false.
570 */
571 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700572 public boolean addFlow(FlowPath flowPath, FlowId flowId,
573 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700574 /*
575 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700576 if (flowPath.flowId().value() == measurementFlowId) {
577 modifiedMeasurementFlowTime = System.nanoTime();
578 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700579 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800580
581 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000582 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800583 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700584 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800585 != null) {
586 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
587 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000588 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800589 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700590 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800591 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
592 flowPath.flowId().toString());
593 }
594 } catch (Exception e) {
595 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700596 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000597
598 StringWriter sw = new StringWriter();
599 e.printStackTrace(new PrintWriter(sw));
600 String stacktrace = sw.toString();
601
602 log.error(":addFlow FlowId:{} failed: {}",
603 flowPath.flowId().toString(),
604 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800605 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700606 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000607 log.error(":addFlow FlowId:{} failed: Flow object not created",
608 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700609 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800610 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700611 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800612
613 //
614 // Set the Flow key:
615 // - flowId
616 //
617 flowObj.setFlowId(flowPath.flowId().toString());
618 flowObj.setType("flow");
619
620 //
621 // Set the Flow attributes:
622 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700623 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800624 // - flowPath.dataPath().srcPort()
625 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700626 // - flowPath.matchSrcMac()
627 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700628 // - flowPath.matchEthernetFrameType()
629 // - flowPath.matchVlanId()
630 // - flowPath.matchVlanPriority()
631 // - flowPath.matchSrcIPv4Net()
632 // - flowPath.matchDstIPv4Net()
633 // - flowPath.matchIpProto()
634 // - flowPath.matchIpToS()
635 // - flowPath.matchSrcTcpUdpPort()
636 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700637 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800638 //
639 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700640 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800641 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
642 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
643 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
644 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700645 if (flowPath.flowEntryMatch().matchSrcMac()) {
646 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
647 }
648 if (flowPath.flowEntryMatch().matchDstMac()) {
649 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
650 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700651 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
652 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
653 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700654 if (flowPath.flowEntryMatch().matchVlanId()) {
655 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
656 }
657 if (flowPath.flowEntryMatch().matchVlanPriority()) {
658 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
659 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700660 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
661 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
662 }
663 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
664 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
665 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700666 if (flowPath.flowEntryMatch().matchIpProto()) {
667 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700668 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700669 if (flowPath.flowEntryMatch().matchIpToS()) {
670 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
671 }
672 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
673 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
674 }
675 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
676 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700677 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700678 if (! flowPath.flowEntryActions().actions().isEmpty()) {
679 flowObj.setActions(flowPath.flowEntryActions().toString());
680 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800681
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700682 if (dataPathSummaryStr != null) {
683 flowObj.setDataPathSummary(dataPathSummaryStr);
684 } else {
685 flowObj.setDataPathSummary("");
686 }
687
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000688 if (found)
689 flowObj.setUserState("FE_USER_MODIFY");
690 else
691 flowObj.setUserState("FE_USER_ADD");
692
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800693 // Flow edges:
694 // HeadFE
695
696
697 //
698 // Flow Entries:
699 // flowPath.dataPath().flowEntries()
700 //
701 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700702 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700703 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700705 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800706 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700707 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800708
709 //
710 // TODO: We need a proper Flow ID allocation mechanism.
711 //
712 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700713
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800714 return true;
715 }
716
717 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700718 * Add a flow entry to the Network MAP.
719 *
720 * @param flowObj the corresponding Flow Path object for the Flow Entry.
721 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700722 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700723 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700724 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700725 // Flow edges
726 // HeadFE (TODO)
727
728 //
729 // Assign the FlowEntry ID.
730 //
731 if ((flowEntry.flowEntryId() == null) ||
732 (flowEntry.flowEntryId().value() == 0)) {
733 long id = getNextFlowEntryId();
734 flowEntry.setFlowEntryId(new FlowEntryId(id));
735 }
736
737 IFlowEntry flowEntryObj = null;
738 boolean found = false;
739 try {
740 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700741 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700742 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
743 flowEntry.flowEntryId().toString());
744 found = true;
745 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700746 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700747 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
748 flowEntry.flowEntryId().toString());
749 }
750 } catch (Exception e) {
751 log.error(":addFlow FlowEntryId:{} failed",
752 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700753 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700754 }
755 if (flowEntryObj == null) {
756 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
757 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700758 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700759 }
760
761 //
762 // Set the Flow Entry key:
763 // - flowEntry.flowEntryId()
764 //
765 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
766 flowEntryObj.setType("flow_entry");
767
768 //
769 // Set the Flow Entry Edges and attributes:
770 // - Switch edge
771 // - InPort edge
772 // - OutPort edge
773 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700774 // - flowEntry.dpid()
775 // - flowEntry.flowEntryUserState()
776 // - flowEntry.flowEntrySwitchState()
777 // - flowEntry.flowEntryErrorState()
778 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700779 // - flowEntry.matchSrcMac()
780 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700781 // - flowEntry.matchEthernetFrameType()
782 // - flowEntry.matchVlanId()
783 // - flowEntry.matchVlanPriority()
784 // - flowEntry.matchSrcIPv4Net()
785 // - flowEntry.matchDstIPv4Net()
786 // - flowEntry.matchIpProto()
787 // - flowEntry.matchIpToS()
788 // - flowEntry.matchSrcTcpUdpPort()
789 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700790 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700791 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700792 //
admin944ef4f2013-10-08 17:48:37 -0700793 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700794 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
795 flowEntryObj.setSwitch(sw);
796 if (flowEntry.flowEntryMatch().matchInPort()) {
797 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700798 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700799 flowEntry.flowEntryMatch().inPort().value());
800 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
801 flowEntryObj.setInPort(inport);
802 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700803 if (flowEntry.flowEntryMatch().matchSrcMac()) {
804 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
805 }
806 if (flowEntry.flowEntryMatch().matchDstMac()) {
807 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
808 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700809 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
810 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
811 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700812 if (flowEntry.flowEntryMatch().matchVlanId()) {
813 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
814 }
815 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
816 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
817 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700818 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
819 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
820 }
821 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
822 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
823 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700824 if (flowEntry.flowEntryMatch().matchIpProto()) {
825 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700826 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700827 if (flowEntry.flowEntryMatch().matchIpToS()) {
828 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
829 }
830 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
831 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
832 }
833 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
834 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700835 }
836
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700837 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700838 if (fa.actionOutput() != null) {
839 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700840 op.searchPort(flowEntry.dpid().toString(),
841 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700842 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700843 flowEntryObj.setOutPort(outport);
844 }
845 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700846 if (! flowEntry.flowEntryActions().isEmpty()) {
847 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
848 }
849
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700850 // TODO: Hacks with hard-coded state names!
851 if (found)
852 flowEntryObj.setUserState("FE_USER_MODIFY");
853 else
854 flowEntryObj.setUserState("FE_USER_ADD");
855 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
856 //
857 // TODO: Take care of the FlowEntryErrorState.
858 //
859
860 // Flow Entries edges:
861 // Flow
862 // NextFE (TODO)
863 if (! found) {
864 flowObj.addFlowEntry(flowEntryObj);
865 flowEntryObj.setFlow(flowObj);
866 }
867
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700868 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700869 }
870
871 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000872 * Delete all previously added flows.
873 *
874 * @return true on success, otherwise false.
875 */
876 @Override
877 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000878 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
879 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000880
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000881 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700882 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000883 for (IFlowPath flowPathObj : allFlowPaths) {
884 if (flowPathObj == null)
885 continue;
886 String flowIdStr = flowPathObj.getFlowId();
887 if (flowIdStr == null)
888 continue;
889 FlowId flowId = new FlowId(flowIdStr);
890 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000891 }
892
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000893 // Delete all flows one-by-one
894 for (FlowId flowId : concurrentAllFlowIds)
895 deleteFlow(flowId);
896
897 /*
898 * TODO: A faster mechanism to delete the Flow Paths by using
899 * a number of threads. Commented-out for now.
900 */
901 /*
902 //
903 // Create the threads to delete the Flow Paths
904 //
Yuta HIGUCHI6f0e4392013-10-09 17:43:34 -0700905 List<Thread> threads = new LinkedList<Thread>();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000906 for (int i = 0; i < 10; i++) {
907 Thread thread = new Thread(new Runnable() {
908 @Override
909 public void run() {
910 while (true) {
911 FlowId flowId = concurrentAllFlowIds.poll();
912 if (flowId == null)
913 return;
914 deleteFlow(flowId);
915 }
916 }}, "Delete All Flow Paths");
917 threads.add(thread);
918 }
919
920 // Start processing
921 for (Thread thread : threads) {
922 thread.start();
923 }
924
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000925 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000926 for (Thread thread : threads) {
927 try {
928 thread.join();
929 } catch (InterruptedException e) {
930 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
931 }
932 }
933 */
934
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000935 return true;
936 }
937
938 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800939 * Delete a previously added flow.
940 *
941 * @param flowId the Flow ID of the flow to delete.
942 * @return true on success, otherwise false.
943 */
944 @Override
945 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700946 /*
947 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700948 if (flowId.value() == measurementFlowId) {
949 modifiedMeasurementFlowTime = System.nanoTime();
950 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700951 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700952
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800953 IFlowPath flowObj = null;
954 //
955 // We just mark the entries for deletion,
956 // and let the switches remove each individual entry after
957 // it has been removed from the switches.
958 //
959 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700960 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800961 != null) {
962 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
963 flowId.toString());
964 } else {
965 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
966 flowId.toString());
967 }
968 } catch (Exception e) {
969 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700970 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800971 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
972 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700973 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700974 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800975 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700976 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800977
978 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000979 // Find and mark for deletion all Flow Entries,
980 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800981 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000982 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800983 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
984 boolean empty = true; // TODO: an ugly hack
985 for (IFlowEntry flowEntryObj : flowEntries) {
986 empty = false;
987 // flowObj.removeFlowEntry(flowEntryObj);
988 // conn.utils().removeFlowEntry(conn, flowEntryObj);
989 flowEntryObj.setUserState("FE_USER_DELETE");
990 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
991 }
992 // Remove from the database empty flows
993 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700994 op.removeFlowPath(flowObj);
995 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800996
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800997 return true;
998 }
999
1000 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001001 * Clear the state for all previously added flows.
1002 *
1003 * @return true on success, otherwise false.
1004 */
1005 @Override
1006 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001007 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001008
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001009 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001010 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001011 for (IFlowPath flowPathObj : allFlowPaths) {
1012 if (flowPathObj == null)
1013 continue;
1014 String flowIdStr = flowPathObj.getFlowId();
1015 if (flowIdStr == null)
1016 continue;
1017 FlowId flowId = new FlowId(flowIdStr);
1018 allFlowIds.add(flowId);
1019 }
1020
1021 // Clear all flows one-by-one
1022 for (FlowId flowId : allFlowIds) {
1023 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001024 }
1025
1026 return true;
1027 }
1028
1029 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001030 * Clear the state for a previously added flow.
1031 *
1032 * @param flowId the Flow ID of the flow to clear.
1033 * @return true on success, otherwise false.
1034 */
1035 @Override
1036 public boolean clearFlow(FlowId flowId) {
1037 IFlowPath flowObj = null;
1038 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001039 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001040 != null) {
1041 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1042 flowId.toString());
1043 } else {
1044 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1045 flowId.toString());
1046 }
1047 } catch (Exception e) {
1048 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001049 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001050 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1051 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001052 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001053 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001054 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001055 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001056
1057 //
1058 // Remove all Flow Entries
1059 //
1060 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1061 for (IFlowEntry flowEntryObj : flowEntries) {
1062 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001063 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001064 }
1065 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001066 op.removeFlowPath(flowObj);
1067 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001068
1069 return true;
1070 }
1071
1072 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001073 * Get a previously added flow.
1074 *
1075 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001076 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001077 */
1078 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001079 public FlowPath getFlow(FlowId flowId) {
1080 IFlowPath flowObj = null;
1081 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001082 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001083 != null) {
1084 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1085 flowId.toString());
1086 } else {
1087 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1088 flowId.toString());
1089 }
1090 } catch (Exception e) {
1091 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001092 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001093 log.error(":getFlow FlowId:{} failed", flowId.toString());
1094 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001095 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001096 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001097 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001098 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001099
1100 //
1101 // Extract the Flow state
1102 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001103 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001104 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001105
1106 return flowPath;
1107 }
1108
1109 /**
1110 * Get all previously added flows by a specific installer for a given
1111 * data path endpoints.
1112 *
1113 * @param installerId the Caller ID of the installer of the flow to get.
1114 * @param dataPathEndpoints the data path endpoints of the flow to get.
1115 * @return the Flow Paths if found, otherwise null.
1116 */
1117 @Override
1118 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1119 DataPathEndpoints dataPathEndpoints) {
1120 //
1121 // TODO: The implementation below is not optimal:
1122 // We fetch all flows, and then return only the subset that match
1123 // the query conditions.
1124 // We should use the appropriate Titan/Gremlin query to filter-out
1125 // the flows as appropriate.
1126 //
1127 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001128 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001129
1130 if (allFlows == null) {
1131 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001132 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001133 }
1134
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001135 for (FlowPath flow : allFlows) {
1136 //
1137 // TODO: String-based comparison is sub-optimal.
1138 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001139 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001140 //
1141 if (! flow.installerId().toString().equals(installerId.toString()))
1142 continue;
1143 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1144 continue;
1145 }
1146 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1147 continue;
1148 }
1149 flowPaths.add(flow);
1150 }
1151
1152 if (flowPaths.isEmpty()) {
1153 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001154 } else {
1155 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1156 }
1157
1158 return flowPaths;
1159 }
1160
1161 /**
1162 * Get all installed flows by all installers for given data path endpoints.
1163 *
1164 * @param dataPathEndpoints the data path endpoints of the flows to get.
1165 * @return the Flow Paths if found, otherwise null.
1166 */
1167 @Override
1168 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1169 //
1170 // TODO: The implementation below is not optimal:
1171 // We fetch all flows, and then return only the subset that match
1172 // the query conditions.
1173 // We should use the appropriate Titan/Gremlin query to filter-out
1174 // the flows as appropriate.
1175 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001176 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1177 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001178
1179 if (allFlows == null) {
1180 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001181 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001182 }
1183
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001184 for (FlowPath flow : allFlows) {
1185 //
1186 // TODO: String-based comparison is sub-optimal.
1187 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001188 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001189 //
1190 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1191 continue;
1192 }
1193 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1194 continue;
1195 }
1196 flowPaths.add(flow);
1197 }
1198
1199 if (flowPaths.isEmpty()) {
1200 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001201 } else {
1202 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1203 }
1204
1205 return flowPaths;
1206 }
1207
1208 /**
admin944ef4f2013-10-08 17:48:37 -07001209 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001210 *
admin944ef4f2013-10-08 17:48:37 -07001211 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001212 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001213 * @return the Flow Paths if found, otherwise null.
1214 */
1215 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001216 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001217
admin944ef4f2013-10-08 17:48:37 -07001218 //
1219 // TODO: The implementation below is not optimal:
1220 // We fetch all flows, and then return only the subset that match
1221 // the query conditions.
1222 // We should use the appropriate Titan/Gremlin query to filter-out
1223 // the flows as appropriate.
1224 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001225 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001226
Jonathan Hart01f2d272013-04-04 20:03:46 -07001227 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1228
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001229 Collections.sort(flowPathsWithoutFlowEntries,
1230 new Comparator<IFlowPath>(){
1231 @Override
1232 public int compare(IFlowPath first, IFlowPath second) {
1233 // TODO Auto-generated method stub
1234 long result = new FlowId(first.getFlowId()).value()
1235 - new FlowId(second.getFlowId()).value();
1236 if (result > 0) return 1;
1237 else if (result < 0) return -1;
1238 else return 0;
1239 }
1240 }
1241 );
1242
Jonathan Hart01f2d272013-04-04 20:03:46 -07001243 return flowPathsWithoutFlowEntries;
1244
1245 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001246 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001247
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001248 if (allFlows == null) {
1249 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001250 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001251 }
1252
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001253 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001254
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001255 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001256 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001257
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001258 // start from desired flowId
1259 if (flow.flowId().value() < flowId.value()) {
1260 continue;
1261 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001262
1263 // Summarize by making null flow entry fields that are not relevant to report
1264 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1265 flowEntry.setFlowEntryActions(null);
1266 flowEntry.setFlowEntryMatch(null);
1267 }
1268
1269 flowPaths.add(flow);
1270 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1271 break;
1272 }
1273 }
1274
1275 if (flowPaths.isEmpty()) {
1276 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001277 } else {
1278 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1279 }
1280
1281 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001282 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001283 }
1284
1285 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001286 * Get all installed flows by all installers.
1287 *
1288 * @return the Flow Paths if found, otherwise null.
1289 */
1290 @Override
1291 public ArrayList<FlowPath> getAllFlows() {
1292 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001293 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001294
1295 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001296 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001297 log.debug("Get all FlowPaths: found FlowPaths");
1298 } else {
1299 log.debug("Get all FlowPaths: no FlowPaths found");
1300 }
1301 } catch (Exception e) {
1302 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001303 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001304 log.error(":getAllFlowPaths failed");
1305 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001306 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001307 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001308 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001309 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001310
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001311 for (IFlowPath flowObj : flowPathsObj) {
1312 //
1313 // Extract the Flow state
1314 //
1315 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001316 if (flowPath != null)
1317 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001318 }
1319
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001320 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001321
1322 return flowPaths;
1323 }
admin944ef4f2013-10-08 17:48:37 -07001324
1325 /**
1326 * Get all Flows information, without the associated Flow Entries.
1327 *
1328 * @return all Flows information, without the associated Flow Entries.
1329 */
1330 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001331 Iterable<IFlowPath> flowPathsObj = null;
1332 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001333
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001334 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001335
Jonathan Hart01f2d272013-04-04 20:03:46 -07001336 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001337 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001338 log.debug("Get all FlowPaths: found FlowPaths");
1339 } else {
1340 log.debug("Get all FlowPaths: no FlowPaths found");
1341 }
1342 } catch (Exception e) {
1343 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001344 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001345 log.error(":getAllFlowPaths failed");
1346 }
1347 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1348 return new ArrayList<IFlowPath>(); // No Flows found
1349 }
1350
1351 for (IFlowPath flowObj : flowPathsObj){
1352 flowPathsObjArray.add(flowObj);
1353 }
1354 /*
Yuta HIGUCHI1e3eba82013-10-09 17:34:54 -07001355 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001356 for (IFlowPath flowObj : flowPathsObj) {
1357 //
1358 // Extract the Flow state
1359 //
1360 FlowPath flowPath = extractFlowPath(flowObj);
1361 if (flowPath != null)
1362 flowPaths.add(flowPath);
1363 }
1364 */
1365
1366 //conn.endTx(Transaction.COMMIT);
1367
1368 return flowPathsObjArray;
1369 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001370
1371 /**
1372 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1373 *
1374 * @param flowObj the object to extract the Flow Path State from.
1375 * @return the extracted Flow Path State.
1376 */
1377 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001378 //
1379 // Extract the Flow state
1380 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001381 String flowIdStr = flowObj.getFlowId();
1382 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001383 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001384 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001385 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001386 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001387 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001388
1389 if ((flowIdStr == null) ||
1390 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001391 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001392 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001393 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001394 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001395 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001396 // TODO: A work-around, becauuse of some bogus database objects
1397 return null;
1398 }
1399
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001400 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001401 flowPath.setFlowId(new FlowId(flowIdStr));
1402 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001403 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001404 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001405 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001406 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001407 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001408 //
1409 // Extract the match conditions common for all Flow Entries
1410 //
1411 {
1412 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001413 String matchSrcMac = flowObj.getMatchSrcMac();
1414 if (matchSrcMac != null)
1415 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1416 String matchDstMac = flowObj.getMatchDstMac();
1417 if (matchDstMac != null)
1418 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001419 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1420 if (matchEthernetFrameType != null)
1421 match.enableEthernetFrameType(matchEthernetFrameType);
1422 Short matchVlanId = flowObj.getMatchVlanId();
1423 if (matchVlanId != null)
1424 match.enableVlanId(matchVlanId);
1425 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1426 if (matchVlanPriority != null)
1427 match.enableVlanPriority(matchVlanPriority);
1428 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1429 if (matchSrcIPv4Net != null)
1430 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1431 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1432 if (matchDstIPv4Net != null)
1433 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1434 Byte matchIpProto = flowObj.getMatchIpProto();
1435 if (matchIpProto != null)
1436 match.enableIpProto(matchIpProto);
1437 Byte matchIpToS = flowObj.getMatchIpToS();
1438 if (matchIpToS != null)
1439 match.enableIpToS(matchIpToS);
1440 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1441 if (matchSrcTcpUdpPort != null)
1442 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1443 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1444 if (matchDstTcpUdpPort != null)
1445 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1446
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001447 flowPath.setFlowEntryMatch(match);
1448 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001449 //
1450 // Extract the actions for the first Flow Entry
1451 //
1452 {
1453 String actionsStr = flowObj.getActions();
1454 if (actionsStr != null) {
1455 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1456 flowPath.setFlowEntryActions(flowEntryActions);
1457 }
1458 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001459
1460 //
1461 // Extract all Flow Entries
1462 //
1463 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1464 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001465 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1466 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001467 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001468 flowPath.dataPath().flowEntries().add(flowEntry);
1469 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001470
1471 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001472 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001473
1474 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001475 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1476 *
1477 * @param flowEntryObj the object to extract the Flow Entry State from.
1478 * @return the extracted Flow Entry State.
1479 */
1480 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1481 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1482 String switchDpidStr = flowEntryObj.getSwitchDpid();
1483 String userState = flowEntryObj.getUserState();
1484 String switchState = flowEntryObj.getSwitchState();
1485
1486 if ((flowEntryIdStr == null) ||
1487 (switchDpidStr == null) ||
1488 (userState == null) ||
1489 (switchState == null)) {
1490 // TODO: A work-around, becauuse of some bogus database objects
1491 return null;
1492 }
1493
1494 FlowEntry flowEntry = new FlowEntry();
1495 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1496 flowEntry.setDpid(new Dpid(switchDpidStr));
1497
1498 //
1499 // Extract the match conditions
1500 //
1501 FlowEntryMatch match = new FlowEntryMatch();
1502 Short matchInPort = flowEntryObj.getMatchInPort();
1503 if (matchInPort != null)
1504 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001505 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1506 if (matchSrcMac != null)
1507 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1508 String matchDstMac = flowEntryObj.getMatchDstMac();
1509 if (matchDstMac != null)
1510 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001511 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1512 if (matchEthernetFrameType != null)
1513 match.enableEthernetFrameType(matchEthernetFrameType);
1514 Short matchVlanId = flowEntryObj.getMatchVlanId();
1515 if (matchVlanId != null)
1516 match.enableVlanId(matchVlanId);
1517 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1518 if (matchVlanPriority != null)
1519 match.enableVlanPriority(matchVlanPriority);
1520 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1521 if (matchSrcIPv4Net != null)
1522 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1523 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1524 if (matchDstIPv4Net != null)
1525 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1526 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1527 if (matchIpProto != null)
1528 match.enableIpProto(matchIpProto);
1529 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1530 if (matchIpToS != null)
1531 match.enableIpToS(matchIpToS);
1532 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1533 if (matchSrcTcpUdpPort != null)
1534 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1535 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1536 if (matchDstTcpUdpPort != null)
1537 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001538 flowEntry.setFlowEntryMatch(match);
1539
1540 //
1541 // Extract the actions
1542 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001543 FlowEntryActions actions = new FlowEntryActions();
1544 String actionsStr = flowEntryObj.getActions();
1545 if (actionsStr != null)
1546 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001547 flowEntry.setFlowEntryActions(actions);
1548 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1549 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1550 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001551 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001552 //
1553 return flowEntry;
1554 }
1555
1556 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001557 * Add and maintain a shortest-path flow.
1558 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001559 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001560 *
1561 * @param flowPath the Flow Path with the endpoints and the match
1562 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001563 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001564 */
1565 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001566 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001567 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001568 // Don't do the shortest path computation here.
1569 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001570 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001571
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001572 // We need the DataPath to populate the Network MAP
1573 DataPath dataPath = new DataPath();
1574 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1575 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001576
1577 //
1578 // Prepare the computed Flow Path
1579 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001580 FlowPath computedFlowPath = new FlowPath();
1581 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1582 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001583 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001584 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001585 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001586 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001587
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001588 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001589 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001590 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001591 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001592
1593 // TODO: Mark the flow for maintenance purpose
1594
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001595 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001596 }
1597
1598 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001599 * Reconcile a flow.
1600 *
1601 * @param flowObj the flow that needs to be reconciliated.
1602 * @param newDataPath the new data path to use.
1603 * @return true on success, otherwise false.
1604 */
1605 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001606
1607 //
1608 // Set the incoming port matching and the outgoing port output
1609 // actions for each flow entry.
1610 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001611 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001612 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1613 // Set the incoming port matching
1614 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1615 flowEntry.setFlowEntryMatch(flowEntryMatch);
1616 flowEntryMatch.enableInPort(flowEntry.inPort());
1617
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001618 //
1619 // Set the actions
1620 //
1621 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1622 //
1623 // If the first Flow Entry, copy the Flow Path actions to it
1624 //
1625 if (idx == 0) {
1626 String actionsStr = flowObj.getActions();
1627 if (actionsStr != null) {
1628 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1629 for (FlowEntryAction action : flowActions.actions())
1630 flowEntryActions.addAction(action);
1631 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001632 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001633 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001634 //
1635 // Add the outgoing port output action
1636 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001637 FlowEntryAction flowEntryAction = new FlowEntryAction();
1638 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001639 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001640 }
1641
1642 //
1643 // Remove the old Flow Entries, and add the new Flow Entries
1644 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001645 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001646 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001647 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001648 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001649 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001650 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001651 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001652 }
1653
1654 //
1655 // Set the Data Path Summary
1656 //
1657 String dataPathSummaryStr = newDataPath.dataPathSummary();
1658 flowObj.setDataPathSummary(dataPathSummaryStr);
1659
1660 return true;
1661 }
1662
1663 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001664 * Reconcile all flows in a set.
1665 *
1666 * @param flowObjSet the set of flows that need to be reconciliated.
1667 */
1668 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1669 if (! flowObjSet.iterator().hasNext())
1670 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001671 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001672 }
1673
1674 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001675 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001676 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001677 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001678 * @param flowObj the flow path object for the flow entry to install.
1679 * @param flowEntryObj the flow entry object to install.
1680 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001681 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001682 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1683 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001684 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1685 if (flowEntryIdStr == null)
1686 return false;
1687 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001688 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001689 if (userState == null)
1690 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001691
1692 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001693 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001694 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001695 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1696 .getMessage(OFType.FLOW_MOD);
1697 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001698
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001699 short flowModCommand = OFFlowMod.OFPFC_ADD;
1700 if (userState.equals("FE_USER_ADD")) {
1701 flowModCommand = OFFlowMod.OFPFC_ADD;
1702 } else if (userState.equals("FE_USER_MODIFY")) {
1703 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1704 } else if (userState.equals("FE_USER_DELETE")) {
1705 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1706 } else {
1707 // Unknown user state. Ignore the entry
1708 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1709 flowEntryId.toString(), userState);
1710 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001711 }
1712
1713 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001714 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001715 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001716 // NOTE: The Flow matching conditions common for all Flow Entries are
1717 // used ONLY if a Flow Entry does NOT have the corresponding matching
1718 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001719 //
1720 OFMatch match = new OFMatch();
1721 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001722
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001723 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001724 Short matchInPort = flowEntryObj.getMatchInPort();
1725 if (matchInPort != null) {
1726 match.setInputPort(matchInPort);
1727 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1728 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001729
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001730 // Match the Source MAC address
1731 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1732 if (matchSrcMac == null)
1733 matchSrcMac = flowObj.getMatchSrcMac();
1734 if (matchSrcMac != null) {
1735 match.setDataLayerSource(matchSrcMac);
1736 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1737 }
1738
1739 // Match the Destination MAC address
1740 String matchDstMac = flowEntryObj.getMatchDstMac();
1741 if (matchDstMac == null)
1742 matchDstMac = flowObj.getMatchDstMac();
1743 if (matchDstMac != null) {
1744 match.setDataLayerDestination(matchDstMac);
1745 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1746 }
1747
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001748 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001749 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1750 if (matchEthernetFrameType == null)
1751 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1752 if (matchEthernetFrameType != null) {
1753 match.setDataLayerType(matchEthernetFrameType);
1754 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1755 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001756
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001757 // Match the VLAN ID
1758 Short matchVlanId = flowEntryObj.getMatchVlanId();
1759 if (matchVlanId == null)
1760 matchVlanId = flowObj.getMatchVlanId();
1761 if (matchVlanId != null) {
1762 match.setDataLayerVirtualLan(matchVlanId);
1763 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1764 }
1765
1766 // Match the VLAN priority
1767 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1768 if (matchVlanPriority == null)
1769 matchVlanPriority = flowObj.getMatchVlanPriority();
1770 if (matchVlanPriority != null) {
1771 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1772 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1773 }
1774
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001775 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001776 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1777 if (matchSrcIPv4Net == null)
1778 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1779 if (matchSrcIPv4Net != null) {
1780 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1781 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001782
1783 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001784 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1785 if (matchDstIPv4Net == null)
1786 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1787 if (matchDstIPv4Net != null) {
1788 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1789 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001790
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001791 // Match the IP protocol
1792 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1793 if (matchIpProto == null)
1794 matchIpProto = flowObj.getMatchIpProto();
1795 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001796 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001797 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001798 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001799
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001800 // Match the IP ToS (DSCP field, 6 bits)
1801 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1802 if (matchIpToS == null)
1803 matchIpToS = flowObj.getMatchIpToS();
1804 if (matchIpToS != null) {
1805 match.setNetworkTypeOfService(matchIpToS);
1806 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1807 }
1808
1809 // Match the Source TCP/UDP port
1810 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1811 if (matchSrcTcpUdpPort == null)
1812 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1813 if (matchSrcTcpUdpPort != null) {
1814 match.setTransportSource(matchSrcTcpUdpPort);
1815 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1816 }
1817
1818 // Match the Destination TCP/UDP port
1819 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1820 if (matchDstTcpUdpPort == null)
1821 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1822 if (matchDstTcpUdpPort != null) {
1823 match.setTransportDestination(matchDstTcpUdpPort);
1824 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001825 }
1826
1827 //
1828 // Fetch the actions
1829 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001830 Short actionOutputPort = null;
1831 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1832 int actionsLen = 0;
1833 FlowEntryActions flowEntryActions = null;
1834 String actionsStr = flowEntryObj.getActions();
1835 if (actionsStr != null)
1836 flowEntryActions = new FlowEntryActions(actionsStr);
1837 for (FlowEntryAction action : flowEntryActions.actions()) {
1838 ActionOutput actionOutput = action.actionOutput();
1839 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1840 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1841 ActionStripVlan actionStripVlan = action.actionStripVlan();
1842 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1843 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1844 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1845 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1846 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1847 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1848 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1849 ActionEnqueue actionEnqueue = action.actionEnqueue();
1850
1851 if (actionOutput != null) {
1852 actionOutputPort = actionOutput.port().value();
1853 // XXX: The max length is hard-coded for now
1854 OFActionOutput ofa =
1855 new OFActionOutput(actionOutput.port().value(),
1856 (short)0xffff);
1857 openFlowActions.add(ofa);
1858 actionsLen += ofa.getLength();
1859 }
1860
1861 if (actionSetVlanId != null) {
1862 OFActionVirtualLanIdentifier ofa =
1863 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1864 openFlowActions.add(ofa);
1865 actionsLen += ofa.getLength();
1866 }
1867
1868 if (actionSetVlanPriority != null) {
1869 OFActionVirtualLanPriorityCodePoint ofa =
1870 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1871 openFlowActions.add(ofa);
1872 actionsLen += ofa.getLength();
1873 }
1874
1875 if (actionStripVlan != null) {
1876 if (actionStripVlan.stripVlan() == true) {
1877 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1878 openFlowActions.add(ofa);
1879 actionsLen += ofa.getLength();
1880 }
1881 }
1882
1883 if (actionSetEthernetSrcAddr != null) {
1884 OFActionDataLayerSource ofa =
1885 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1886 openFlowActions.add(ofa);
1887 actionsLen += ofa.getLength();
1888 }
1889
1890 if (actionSetEthernetDstAddr != null) {
1891 OFActionDataLayerDestination ofa =
1892 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1893 openFlowActions.add(ofa);
1894 actionsLen += ofa.getLength();
1895 }
1896
1897 if (actionSetIPv4SrcAddr != null) {
1898 OFActionNetworkLayerSource ofa =
1899 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1900 openFlowActions.add(ofa);
1901 actionsLen += ofa.getLength();
1902 }
1903
1904 if (actionSetIPv4DstAddr != null) {
1905 OFActionNetworkLayerDestination ofa =
1906 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1907 openFlowActions.add(ofa);
1908 actionsLen += ofa.getLength();
1909 }
1910
1911 if (actionSetIpToS != null) {
1912 OFActionNetworkTypeOfService ofa =
1913 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1914 openFlowActions.add(ofa);
1915 actionsLen += ofa.getLength();
1916 }
1917
1918 if (actionSetTcpUdpSrcPort != null) {
1919 OFActionTransportLayerSource ofa =
1920 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1921 openFlowActions.add(ofa);
1922 actionsLen += ofa.getLength();
1923 }
1924
1925 if (actionSetTcpUdpDstPort != null) {
1926 OFActionTransportLayerDestination ofa =
1927 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1928 openFlowActions.add(ofa);
1929 actionsLen += ofa.getLength();
1930 }
1931
1932 if (actionEnqueue != null) {
1933 OFActionEnqueue ofa =
1934 new OFActionEnqueue(actionEnqueue.port().value(),
1935 actionEnqueue.queueId());
1936 openFlowActions.add(ofa);
1937 actionsLen += ofa.getLength();
1938 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001939 }
1940
1941 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1942 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1943 .setPriority(PRIORITY_DEFAULT)
1944 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1945 .setCookie(cookie)
1946 .setCommand(flowModCommand)
1947 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001948 .setActions(openFlowActions)
1949 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001950 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1951 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1952 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1953 if (actionOutputPort != null)
1954 fm.setOutPort(actionOutputPort);
1955 }
1956
1957 //
1958 // TODO: Set the following flag
1959 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1960 // See method ForwardingBase::pushRoute()
1961 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001962
1963 //
1964 // Write the message to the switch
1965 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001966 log.debug("MEASUREMENT: Installing flow entry " + userState +
1967 " into switch DPID: " +
1968 mySwitch.getStringId() +
1969 " flowEntryId: " + flowEntryId.toString() +
1970 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1971 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1972 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001973 try {
1974 messageDamper.write(mySwitch, fm, null);
1975 mySwitch.flush();
1976 //
1977 // TODO: We should use the OpenFlow Barrier mechanism
1978 // to check for errors, and update the SwitchState
1979 // for a flow entry after the Barrier message is
1980 // is received.
1981 //
1982 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1983 } catch (IOException e) {
1984 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001985 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001986 }
1987
1988 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001989 }
1990
1991 /**
1992 * Install a Flow Entry on a switch.
1993 *
1994 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001995 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001996 * @param flowEntry the flow entry to install.
1997 * @return true on success, otherwise false.
1998 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001999 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2000 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002001 //
2002 // Create the OpenFlow Flow Modification Entry to push
2003 //
2004 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
2005 .getMessage(OFType.FLOW_MOD);
2006 long cookie = flowEntry.flowEntryId().value();
2007
2008 short flowModCommand = OFFlowMod.OFPFC_ADD;
2009 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
2010 flowModCommand = OFFlowMod.OFPFC_ADD;
2011 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
2012 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
2013 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
2014 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
2015 } else {
2016 // Unknown user state. Ignore the entry
2017 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
2018 flowEntry.flowEntryId().toString(),
2019 flowEntry.flowEntryUserState());
2020 return false;
2021 }
2022
2023 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002024 // Fetch the match conditions.
2025 //
2026 // NOTE: The Flow matching conditions common for all Flow Entries are
2027 // used ONLY if a Flow Entry does NOT have the corresponding matching
2028 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002029 //
2030 OFMatch match = new OFMatch();
2031 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002032 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
2033 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
2034
2035 // Match the Incoming Port
2036 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002037 if (matchInPort != null) {
2038 match.setInputPort(matchInPort.value());
2039 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
2040 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002041
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002042 // Match the Source MAC address
2043 MACAddress matchSrcMac = flowEntryMatch.srcMac();
2044 if ((matchSrcMac == null) && (flowPathMatch != null)) {
2045 matchSrcMac = flowPathMatch.srcMac();
2046 }
2047 if (matchSrcMac != null) {
2048 match.setDataLayerSource(matchSrcMac.toString());
2049 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2050 }
2051
2052 // Match the Destination MAC address
2053 MACAddress matchDstMac = flowEntryMatch.dstMac();
2054 if ((matchDstMac == null) && (flowPathMatch != null)) {
2055 matchDstMac = flowPathMatch.dstMac();
2056 }
2057 if (matchDstMac != null) {
2058 match.setDataLayerDestination(matchDstMac.toString());
2059 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2060 }
2061
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002062 // Match the Ethernet Frame Type
2063 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2064 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2065 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2066 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002067 if (matchEthernetFrameType != null) {
2068 match.setDataLayerType(matchEthernetFrameType);
2069 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2070 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002071
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002072 // Match the VLAN ID
2073 Short matchVlanId = flowEntryMatch.vlanId();
2074 if ((matchVlanId == null) && (flowPathMatch != null)) {
2075 matchVlanId = flowPathMatch.vlanId();
2076 }
2077 if (matchVlanId != null) {
2078 match.setDataLayerVirtualLan(matchVlanId);
2079 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2080 }
2081
2082 // Match the VLAN priority
2083 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2084 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2085 matchVlanPriority = flowPathMatch.vlanPriority();
2086 }
2087 if (matchVlanPriority != null) {
2088 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2089 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2090 }
2091
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002092 // Match the Source IPv4 Network prefix
2093 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2094 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2095 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2096 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002097 if (matchSrcIPv4Net != null) {
2098 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2099 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002100
2101 // Natch the Destination IPv4 Network prefix
2102 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2103 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2104 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2105 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002106 if (matchDstIPv4Net != null) {
2107 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2108 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002109
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002110 // Match the IP protocol
2111 Byte matchIpProto = flowEntryMatch.ipProto();
2112 if ((matchIpProto == null) && (flowPathMatch != null)) {
2113 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002114 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002115 if (matchIpProto != null) {
2116 match.setNetworkProtocol(matchIpProto);
2117 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002118 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002119
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002120 // Match the IP ToS (DSCP field, 6 bits)
2121 Byte matchIpToS = flowEntryMatch.ipToS();
2122 if ((matchIpToS == null) && (flowPathMatch != null)) {
2123 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002124 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002125 if (matchIpToS != null) {
2126 match.setNetworkTypeOfService(matchIpToS);
2127 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2128 }
2129
2130 // Match the Source TCP/UDP port
2131 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2132 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2133 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2134 }
2135 if (matchSrcTcpUdpPort != null) {
2136 match.setTransportSource(matchSrcTcpUdpPort);
2137 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2138 }
2139
2140 // Match the Destination TCP/UDP port
2141 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2142 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2143 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2144 }
2145 if (matchDstTcpUdpPort != null) {
2146 match.setTransportDestination(matchDstTcpUdpPort);
2147 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002148 }
2149
2150 //
2151 // Fetch the actions
2152 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002153 Short actionOutputPort = null;
2154 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2155 int actionsLen = 0;
2156 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002157 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002158 for (FlowEntryAction action : flowEntryActions.actions()) {
2159 ActionOutput actionOutput = action.actionOutput();
2160 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2161 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2162 ActionStripVlan actionStripVlan = action.actionStripVlan();
2163 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2164 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2165 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2166 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2167 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2168 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2169 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2170 ActionEnqueue actionEnqueue = action.actionEnqueue();
2171
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002172 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002173 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002174 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002175 OFActionOutput ofa =
2176 new OFActionOutput(actionOutput.port().value(),
2177 (short)0xffff);
2178 openFlowActions.add(ofa);
2179 actionsLen += ofa.getLength();
2180 }
2181
2182 if (actionSetVlanId != null) {
2183 OFActionVirtualLanIdentifier ofa =
2184 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2185 openFlowActions.add(ofa);
2186 actionsLen += ofa.getLength();
2187 }
2188
2189 if (actionSetVlanPriority != null) {
2190 OFActionVirtualLanPriorityCodePoint ofa =
2191 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2192 openFlowActions.add(ofa);
2193 actionsLen += ofa.getLength();
2194 }
2195
2196 if (actionStripVlan != null) {
2197 if (actionStripVlan.stripVlan() == true) {
2198 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2199 openFlowActions.add(ofa);
2200 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002201 }
2202 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002203
2204 if (actionSetEthernetSrcAddr != null) {
2205 OFActionDataLayerSource ofa =
2206 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2207 openFlowActions.add(ofa);
2208 actionsLen += ofa.getLength();
2209 }
2210
2211 if (actionSetEthernetDstAddr != null) {
2212 OFActionDataLayerDestination ofa =
2213 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2214 openFlowActions.add(ofa);
2215 actionsLen += ofa.getLength();
2216 }
2217
2218 if (actionSetIPv4SrcAddr != null) {
2219 OFActionNetworkLayerSource ofa =
2220 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2221 openFlowActions.add(ofa);
2222 actionsLen += ofa.getLength();
2223 }
2224
2225 if (actionSetIPv4DstAddr != null) {
2226 OFActionNetworkLayerDestination ofa =
2227 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2228 openFlowActions.add(ofa);
2229 actionsLen += ofa.getLength();
2230 }
2231
2232 if (actionSetIpToS != null) {
2233 OFActionNetworkTypeOfService ofa =
2234 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2235 openFlowActions.add(ofa);
2236 actionsLen += ofa.getLength();
2237 }
2238
2239 if (actionSetTcpUdpSrcPort != null) {
2240 OFActionTransportLayerSource ofa =
2241 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2242 openFlowActions.add(ofa);
2243 actionsLen += ofa.getLength();
2244 }
2245
2246 if (actionSetTcpUdpDstPort != null) {
2247 OFActionTransportLayerDestination ofa =
2248 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2249 openFlowActions.add(ofa);
2250 actionsLen += ofa.getLength();
2251 }
2252
2253 if (actionEnqueue != null) {
2254 OFActionEnqueue ofa =
2255 new OFActionEnqueue(actionEnqueue.port().value(),
2256 actionEnqueue.queueId());
2257 openFlowActions.add(ofa);
2258 actionsLen += ofa.getLength();
2259 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002260 }
2261
2262 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2263 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2264 .setPriority(PRIORITY_DEFAULT)
2265 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2266 .setCookie(cookie)
2267 .setCommand(flowModCommand)
2268 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002269 .setActions(openFlowActions)
2270 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2271 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2272 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2273 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2274 if (actionOutputPort != null)
2275 fm.setOutPort(actionOutputPort);
2276 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002277
2278 //
2279 // TODO: Set the following flag
2280 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2281 // See method ForwardingBase::pushRoute()
2282 //
2283
2284 //
2285 // Write the message to the switch
2286 //
2287 try {
2288 messageDamper.write(mySwitch, fm, null);
2289 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002290 //
2291 // TODO: We should use the OpenFlow Barrier mechanism
2292 // to check for errors, and update the SwitchState
2293 // for a flow entry after the Barrier message is
2294 // is received.
2295 //
2296 // TODO: The FlowEntry Object in Titan should be set
2297 // to FE_SWITCH_UPDATED.
2298 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002299 } catch (IOException e) {
2300 log.error("Failure writing flow mod from network map", e);
2301 return false;
2302 }
2303 return true;
2304 }
2305
2306 /**
2307 * Remove a Flow Entry from a switch.
2308 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002309 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002310 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002311 * @param flowEntry the flow entry to remove.
2312 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002313 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002314 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2315 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002316 //
2317 // The installFlowEntry() method implements both installation
2318 // and removal of flow entries.
2319 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002320 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002321 }
2322
2323 /**
2324 * Install a Flow Entry on a remote controller.
2325 *
2326 * TODO: We need it now: Jono
2327 * - For now it will make a REST call to the remote controller.
2328 * - Internally, it needs to know the name of the remote controller.
2329 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002330 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002331 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002332 * @return true on success, otherwise false.
2333 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002334 public boolean installRemoteFlowEntry(FlowPath flowPath,
2335 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002336 // TODO: We need it now: Jono
2337 // - For now it will make a REST call to the remote controller.
2338 // - Internally, it needs to know the name of the remote controller.
2339 return true;
2340 }
2341
2342 /**
2343 * Remove a flow entry on a remote controller.
2344 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002345 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002346 * @param flowEntry the flow entry to remove.
2347 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002348 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002349 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2350 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002351 //
2352 // The installRemoteFlowEntry() method implements both installation
2353 // and removal of flow entries.
2354 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002355 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002356 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002357}