blob: b3b73999f20c5a18751937532def8c941af74272 [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 Radoslavov15954d42013-10-19 15:29:04 -070039import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070040import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070041import net.onrc.onos.ofcontroller.util.CallerId;
42import net.onrc.onos.ofcontroller.util.DataPath;
43import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
44import net.onrc.onos.ofcontroller.util.Dpid;
45import net.onrc.onos.ofcontroller.util.FlowEntry;
46import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070047import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
48import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070049import net.onrc.onos.ofcontroller.util.FlowEntryId;
50import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
51import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
52import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
53import net.onrc.onos.ofcontroller.util.FlowId;
54import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070055import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070056import net.onrc.onos.ofcontroller.util.IPv4Net;
57import net.onrc.onos.ofcontroller.util.Port;
58import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059
60import org.openflow.protocol.OFFlowMod;
61import org.openflow.protocol.OFMatch;
62import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070063import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080064import org.openflow.protocol.OFType;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070065import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
admin944ef4f2013-10-08 17:48:37 -070069/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070070 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070071 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070072public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080073
Toshio Koide9fe1cb22013-06-13 13:51:11 -070074 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080075
76 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070077 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070078 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070079 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080080
81 protected OFMessageDamper messageDamper;
82
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070083 //
84 // TODO: Values copied from elsewhere (class LearningSwitch).
85 // The local copy should go away!
86 //
87 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
88 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
89 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
90 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
91 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080092
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000093 // Flow Entry ID generation state
94 private static Random randomGenerator = new Random();
95 private static int nextFlowEntryIdPrefix = 0;
96 private static int nextFlowEntryIdSuffix = 0;
97 private static long nextFlowEntryId = 0;
98
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070099 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700100 private static long measurementFlowId = 100000;
101 private static String measurementFlowIdStr = "0x186a0"; // 100000
102 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700103 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700104
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800105 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
107
108 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700109 private ScheduledExecutorService mapReaderScheduler;
110 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700111
admin944ef4f2013-10-08 17:48:37 -0700112 /**
113 * Periodic task for reading the Flow Entries and pushing changes
114 * into the switches.
115 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700116 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800117 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700118 try {
119 runImpl();
120 } catch (Exception e) {
121 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700122 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700123 return;
124 }
125 }
126
127 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700128 long startTime = System.nanoTime();
129 int counterAllFlowEntries = 0;
130 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700131
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800132 if (floodlightProvider == null) {
133 log.debug("FloodlightProvider service not found!");
134 return;
135 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000136 Map<Long, IOFSwitch> mySwitches =
137 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700138 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700139 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700140 return;
141 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700142 LinkedList<IFlowEntry> addFlowEntries =
143 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000144 LinkedList<IFlowEntry> deleteFlowEntries =
145 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700146
147 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700148 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700149 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700150 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700151 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000152 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700153 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700154 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700155 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000156
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000157 String dpidStr = flowEntryObj.getSwitchDpid();
158 if (dpidStr == null)
159 continue;
160 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800161 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000162 if (mySwitch == null)
163 continue; // Ignore the entry: not my switch
164
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700165 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700166 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700167 if (flowObj == null)
168 continue; // Should NOT happen
169 if (flowObj.getFlowId() == null)
170 continue; // Invalid entry
171
172 //
173 // NOTE: For now we process the DELETE before the ADD
174 // to cover the more common scenario.
175 // TODO: This is error prone and needs to be fixed!
176 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000177 String userState = flowEntryObj.getUserState();
178 if (userState == null)
179 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700180 if (userState.equals("FE_USER_DELETE")) {
181 // An entry that needs to be deleted.
182 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700183 installFlowEntry(mySwitch, flowObj, flowEntryObj);
184 } else {
185 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700186 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700187 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700188 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700189 // TODO: Commented-out for now
190 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700191 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700192 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700193 processed_measurement_flow = true;
194 }
195 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700196 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700197 }
198
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700199 //
200 // Process the Flow Entries that need to be added
201 //
202 for (IFlowEntry flowEntryObj : addFlowEntries) {
203 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700204 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700205 if (flowObj == null)
206 continue; // Should NOT happen
207 if (flowObj.getFlowId() == null)
208 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700209
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700210 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700211 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000212 if (mySwitch == null)
213 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700214 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800215 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000216
217 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000218 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700219 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000220 //
221 // TODO: We should use the OpenFlow Barrier mechanism
222 // to check for errors, and delete the Flow Entries after the
223 // Barrier message is received.
224 //
225 while (! deleteFlowEntries.isEmpty()) {
226 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
227 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700228 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000229 if (flowObj == null) {
230 log.debug("Did not find FlowPath to be deleted");
231 continue;
232 }
233 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700234 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000235 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700236
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700237 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700238
239 if (processed_measurement_flow) {
240 long estimatedTime =
241 System.nanoTime() - modifiedMeasurementFlowTime;
242 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
243 (double)estimatedTime / 1000000000 + " sec";
244 log.debug(logMsg);
245 }
246
247 long estimatedTime = System.nanoTime() - startTime;
248 double rate = 0.0;
249 if (estimatedTime > 0)
250 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
251 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
252 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
253 counterMyNotUpdatedFlowEntries + " in " +
254 (double)estimatedTime / 1000000000 + " sec: " +
255 rate + " paths/s";
256 log.debug(logMsg);
257 }
258 };
259
admin944ef4f2013-10-08 17:48:37 -0700260 /**
261 * Periodic task for reading the Flow Paths and recomputing the
262 * shortest paths.
263 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700264 final Runnable shortestPathReconcile = new Runnable() {
265 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700266 try {
267 runImpl();
268 } catch (Exception e) {
269 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700270 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700271 return;
272 }
273 }
274
275 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700276 long startTime = System.nanoTime();
277 int counterAllFlowPaths = 0;
278 int counterMyFlowPaths = 0;
279
280 if (floodlightProvider == null) {
281 log.debug("FloodlightProvider service not found!");
282 return;
283 }
284 Map<Long, IOFSwitch> mySwitches =
285 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700286 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700287 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700288 return;
289 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700290 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
291
292 boolean processed_measurement_flow = false;
293
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700294 //
295 // Fetch and recompute the Shortest Path for those
296 // Flow Paths this controller is responsible for.
297 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700298 Topology topology = topologyNetService.newDatabaseTopology();
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 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700363 // NOTE: Using here the regular getDatabaseShortestPath()
364 // method won't work here, because that method calls
365 // internally "conn.endTx(Transaction.COMMIT)", and that
366 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700367 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700368 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700369 // to avoid closing the transaction.
370 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700371 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700372 topologyNetService.getTopologyShortestPath(
373 topology,
374 srcSwitchPort,
375 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000376 if (dataPath == null) {
377 // We need the DataPath to compare the paths
378 dataPath = new DataPath();
379 dataPath.setSrcPort(srcSwitchPort);
380 dataPath.setDstPort(dstSwitchPort);
381 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700382 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000383
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700384 String newDataPathSummaryStr = dataPath.dataPathSummary();
385 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
386 continue; // Nothing changed
387
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700388 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700389 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000390
391 //
392 // Delete all leftover Flows marked for deletion from the
393 // Network MAP.
394 //
395 while (! deleteFlows.isEmpty()) {
396 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700397 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000398 }
399
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700400 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700401
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700402 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700403
404 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700405 long estimatedTime =
406 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700407 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
408 (double)estimatedTime / 1000000000 + " sec";
409 log.debug(logMsg);
410 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700411
412 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700413 double rate = 0.0;
414 if (estimatedTime > 0)
415 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700416 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700417 counterAllFlowPaths + " MyFlowPaths: " +
418 counterMyFlowPaths + " in " +
419 (double)estimatedTime / 1000000000 + " sec: " +
420 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700421 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800422 }
423 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700424
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425
admin944ef4f2013-10-08 17:48:37 -0700426 /**
427 * Initialize the Flow Manager.
428 *
429 * @param conf the Graph Database configuration string.
430 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800431 @Override
432 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700433 op = new GraphDBOperation(conf);
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700434 topologyNetService = new TopologyManager(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800435 }
436
admin944ef4f2013-10-08 17:48:37 -0700437 /**
438 * Shutdown the Flow Manager operation.
439 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800440 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700441 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800442 }
443
admin944ef4f2013-10-08 17:48:37 -0700444 /**
445 * Shutdown the Flow Manager operation.
446 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800447 @Override
448 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700449 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800450 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800451
admin944ef4f2013-10-08 17:48:37 -0700452 /**
453 * Get the collection of offered module services.
454 *
455 * @return the collection of offered module services.
456 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800457 @Override
458 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
459 Collection<Class<? extends IFloodlightService>> l =
460 new ArrayList<Class<? extends IFloodlightService>>();
461 l.add(IFlowService.class);
462 return l;
463 }
464
admin944ef4f2013-10-08 17:48:37 -0700465 /**
466 * Get the collection of implemented services.
467 *
468 * @return the collection of implemented services.
469 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800470 @Override
471 public Map<Class<? extends IFloodlightService>, IFloodlightService>
472 getServiceImpls() {
473 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700474 IFloodlightService> m =
475 new HashMap<Class<? extends IFloodlightService>,
476 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800477 m.put(IFlowService.class, this);
478 return m;
479 }
480
admin944ef4f2013-10-08 17:48:37 -0700481 /**
482 * Get the collection of modules this module depends on.
483 *
484 * @return the collection of modules this module depends on.
485 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800486 @Override
487 public Collection<Class<? extends IFloodlightService>>
488 getModuleDependencies() {
489 Collection<Class<? extends IFloodlightService>> l =
490 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800491 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700492 l.add(INetworkGraphService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800493 l.add(IRestApiService.class);
494 return l;
495 }
496
admin944ef4f2013-10-08 17:48:37 -0700497 /**
498 * Initialize the module.
499 *
500 * @param context the module context to use for the initialization.
501 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800502 @Override
503 public void init(FloodlightModuleContext context)
504 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700505 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800506 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800507 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800508 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
509 EnumSet.of(OFType.FLOW_MOD),
510 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700511
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700512 String conf = "";
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800513 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700514
admin944ef4f2013-10-08 17:48:37 -0700515 mapReaderScheduler = Executors.newScheduledThreadPool(1);
516 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800517 }
518
admin944ef4f2013-10-08 17:48:37 -0700519 /**
520 * Get the next Flow Entry ID to use.
521 *
522 * @return the next Flow Entry ID to use.
523 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700524 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000525 //
526 // Generate the next Flow Entry ID.
527 // NOTE: For now, the higher 32 bits are random, and
528 // the lower 32 bits are sequential.
529 // In the future, we need a better allocation mechanism.
530 //
531 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
532 nextFlowEntryIdPrefix = randomGenerator.nextInt();
533 nextFlowEntryIdSuffix = 0;
534 } else {
535 nextFlowEntryIdSuffix++;
536 }
537 long result = (long)nextFlowEntryIdPrefix << 32;
538 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
539 return result;
540 }
541
admin944ef4f2013-10-08 17:48:37 -0700542 /**
543 * Startup module operation.
544 *
545 * @param context the module context to use for the startup.
546 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800547 @Override
548 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700549 restApi.addRestletRoutable(new FlowWebRoutable());
Jonathan Hart50a94982013-04-10 14:49:51 -0700550
admin944ef4f2013-10-08 17:48:37 -0700551 // Initialize the Flow Entry ID generator
552 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Jonathan Hart50a94982013-04-10 14:49:51 -0700553
admin944ef4f2013-10-08 17:48:37 -0700554 mapReaderScheduler.scheduleAtFixedRate(
555 mapReader, 3, 3, TimeUnit.SECONDS);
556 shortestPathReconcileScheduler.scheduleAtFixedRate(
557 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800558 }
559
560 /**
561 * Add a flow.
562 *
563 * Internally, ONOS will automatically register the installer for
564 * receiving Flow Path Notifications for that path.
565 *
566 * @param flowPath the Flow Path to install.
567 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700568 * @param dataPathSummaryStr the data path summary string if the added
569 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800570 * @return true on success, otherwise false.
571 */
572 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700573 public boolean addFlow(FlowPath flowPath, FlowId flowId,
574 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700575 /*
576 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700577 if (flowPath.flowId().value() == measurementFlowId) {
578 modifiedMeasurementFlowTime = System.nanoTime();
579 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700580 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800581
582 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000583 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700585 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800586 != null) {
587 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
588 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000589 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800590 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700591 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800592 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
593 flowPath.flowId().toString());
594 }
595 } catch (Exception e) {
596 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700597 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000598
599 StringWriter sw = new StringWriter();
600 e.printStackTrace(new PrintWriter(sw));
601 String stacktrace = sw.toString();
602
603 log.error(":addFlow FlowId:{} failed: {}",
604 flowPath.flowId().toString(),
605 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800606 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700607 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000608 log.error(":addFlow FlowId:{} failed: Flow object not created",
609 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700610 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700612 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800613
614 //
615 // Set the Flow key:
616 // - flowId
617 //
618 flowObj.setFlowId(flowPath.flowId().toString());
619 flowObj.setType("flow");
620
621 //
622 // Set the Flow attributes:
623 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700624 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800625 // - flowPath.dataPath().srcPort()
626 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700627 // - flowPath.matchSrcMac()
628 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700629 // - flowPath.matchEthernetFrameType()
630 // - flowPath.matchVlanId()
631 // - flowPath.matchVlanPriority()
632 // - flowPath.matchSrcIPv4Net()
633 // - flowPath.matchDstIPv4Net()
634 // - flowPath.matchIpProto()
635 // - flowPath.matchIpToS()
636 // - flowPath.matchSrcTcpUdpPort()
637 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700638 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800639 //
640 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700641 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
643 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
644 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
645 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700646 if (flowPath.flowEntryMatch().matchSrcMac()) {
647 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
648 }
649 if (flowPath.flowEntryMatch().matchDstMac()) {
650 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
651 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700652 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
653 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
654 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700655 if (flowPath.flowEntryMatch().matchVlanId()) {
656 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
657 }
658 if (flowPath.flowEntryMatch().matchVlanPriority()) {
659 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
660 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700661 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
662 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
663 }
664 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
665 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
666 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700667 if (flowPath.flowEntryMatch().matchIpProto()) {
668 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700669 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700670 if (flowPath.flowEntryMatch().matchIpToS()) {
671 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
672 }
673 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
674 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
675 }
676 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
677 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700678 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700679 if (! flowPath.flowEntryActions().actions().isEmpty()) {
680 flowObj.setActions(flowPath.flowEntryActions().toString());
681 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800682
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700683 if (dataPathSummaryStr != null) {
684 flowObj.setDataPathSummary(dataPathSummaryStr);
685 } else {
686 flowObj.setDataPathSummary("");
687 }
688
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000689 if (found)
690 flowObj.setUserState("FE_USER_MODIFY");
691 else
692 flowObj.setUserState("FE_USER_ADD");
693
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800694 // Flow edges:
695 // HeadFE
696
697
698 //
699 // Flow Entries:
700 // flowPath.dataPath().flowEntries()
701 //
702 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700703 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700704 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800705 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700706 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800707 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700708 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800709
710 //
711 // TODO: We need a proper Flow ID allocation mechanism.
712 //
713 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700714
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800715 return true;
716 }
717
718 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700719 * Add a flow entry to the Network MAP.
720 *
721 * @param flowObj the corresponding Flow Path object for the Flow Entry.
722 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700723 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700724 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700725 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700726 // Flow edges
727 // HeadFE (TODO)
728
729 //
730 // Assign the FlowEntry ID.
731 //
732 if ((flowEntry.flowEntryId() == null) ||
733 (flowEntry.flowEntryId().value() == 0)) {
734 long id = getNextFlowEntryId();
735 flowEntry.setFlowEntryId(new FlowEntryId(id));
736 }
737
738 IFlowEntry flowEntryObj = null;
739 boolean found = false;
740 try {
741 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700742 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700743 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
744 flowEntry.flowEntryId().toString());
745 found = true;
746 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700747 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700748 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
749 flowEntry.flowEntryId().toString());
750 }
751 } catch (Exception e) {
752 log.error(":addFlow FlowEntryId:{} failed",
753 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700754 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700755 }
756 if (flowEntryObj == null) {
757 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
758 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700759 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700760 }
761
762 //
763 // Set the Flow Entry key:
764 // - flowEntry.flowEntryId()
765 //
766 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
767 flowEntryObj.setType("flow_entry");
768
769 //
770 // Set the Flow Entry Edges and attributes:
771 // - Switch edge
772 // - InPort edge
773 // - OutPort edge
774 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700775 // - flowEntry.dpid()
776 // - flowEntry.flowEntryUserState()
777 // - flowEntry.flowEntrySwitchState()
778 // - flowEntry.flowEntryErrorState()
779 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700780 // - flowEntry.matchSrcMac()
781 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700782 // - flowEntry.matchEthernetFrameType()
783 // - flowEntry.matchVlanId()
784 // - flowEntry.matchVlanPriority()
785 // - flowEntry.matchSrcIPv4Net()
786 // - flowEntry.matchDstIPv4Net()
787 // - flowEntry.matchIpProto()
788 // - flowEntry.matchIpToS()
789 // - flowEntry.matchSrcTcpUdpPort()
790 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700791 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700792 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700793 //
admin944ef4f2013-10-08 17:48:37 -0700794 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700795 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
796 flowEntryObj.setSwitch(sw);
797 if (flowEntry.flowEntryMatch().matchInPort()) {
798 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700799 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700800 flowEntry.flowEntryMatch().inPort().value());
801 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
802 flowEntryObj.setInPort(inport);
803 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700804 if (flowEntry.flowEntryMatch().matchSrcMac()) {
805 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
806 }
807 if (flowEntry.flowEntryMatch().matchDstMac()) {
808 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
809 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700810 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
811 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
812 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700813 if (flowEntry.flowEntryMatch().matchVlanId()) {
814 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
815 }
816 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
817 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
818 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700819 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
820 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
821 }
822 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
823 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
824 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700825 if (flowEntry.flowEntryMatch().matchIpProto()) {
826 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700827 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700828 if (flowEntry.flowEntryMatch().matchIpToS()) {
829 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
830 }
831 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
832 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
833 }
834 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
835 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700836 }
837
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700838 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700839 if (fa.actionOutput() != null) {
840 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700841 op.searchPort(flowEntry.dpid().toString(),
842 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700843 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700844 flowEntryObj.setOutPort(outport);
845 }
846 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700847 if (! flowEntry.flowEntryActions().isEmpty()) {
848 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
849 }
850
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700851 // TODO: Hacks with hard-coded state names!
852 if (found)
853 flowEntryObj.setUserState("FE_USER_MODIFY");
854 else
855 flowEntryObj.setUserState("FE_USER_ADD");
856 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
857 //
858 // TODO: Take care of the FlowEntryErrorState.
859 //
860
861 // Flow Entries edges:
862 // Flow
863 // NextFE (TODO)
864 if (! found) {
865 flowObj.addFlowEntry(flowEntryObj);
866 flowEntryObj.setFlow(flowObj);
867 }
868
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700869 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700870 }
871
872 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000873 * Delete all previously added flows.
874 *
875 * @return true on success, otherwise false.
876 */
877 @Override
878 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000879 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
880 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000881
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000882 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700883 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000884 for (IFlowPath flowPathObj : allFlowPaths) {
885 if (flowPathObj == null)
886 continue;
887 String flowIdStr = flowPathObj.getFlowId();
888 if (flowIdStr == null)
889 continue;
890 FlowId flowId = new FlowId(flowIdStr);
891 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000892 }
893
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000894 // Delete all flows one-by-one
895 for (FlowId flowId : concurrentAllFlowIds)
896 deleteFlow(flowId);
897
898 /*
899 * TODO: A faster mechanism to delete the Flow Paths by using
900 * a number of threads. Commented-out for now.
901 */
902 /*
903 //
904 // Create the threads to delete the Flow Paths
905 //
Yuta HIGUCHI6f0e4392013-10-09 17:43:34 -0700906 List<Thread> threads = new LinkedList<Thread>();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000907 for (int i = 0; i < 10; i++) {
908 Thread thread = new Thread(new Runnable() {
909 @Override
910 public void run() {
911 while (true) {
912 FlowId flowId = concurrentAllFlowIds.poll();
913 if (flowId == null)
914 return;
915 deleteFlow(flowId);
916 }
917 }}, "Delete All Flow Paths");
918 threads.add(thread);
919 }
920
921 // Start processing
922 for (Thread thread : threads) {
923 thread.start();
924 }
925
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000926 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000927 for (Thread thread : threads) {
928 try {
929 thread.join();
930 } catch (InterruptedException e) {
931 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
932 }
933 }
934 */
935
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000936 return true;
937 }
938
939 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800940 * Delete a previously added flow.
941 *
942 * @param flowId the Flow ID of the flow to delete.
943 * @return true on success, otherwise false.
944 */
945 @Override
946 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700947 /*
948 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700949 if (flowId.value() == measurementFlowId) {
950 modifiedMeasurementFlowTime = System.nanoTime();
951 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700952 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700953
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800954 IFlowPath flowObj = null;
955 //
956 // We just mark the entries for deletion,
957 // and let the switches remove each individual entry after
958 // it has been removed from the switches.
959 //
960 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700961 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800962 != null) {
963 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
964 flowId.toString());
965 } else {
966 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
967 flowId.toString());
968 }
969 } catch (Exception e) {
970 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700971 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800972 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
973 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700974 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700975 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800976 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700977 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800978
979 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000980 // Find and mark for deletion all Flow Entries,
981 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800982 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000983 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800984 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
985 boolean empty = true; // TODO: an ugly hack
986 for (IFlowEntry flowEntryObj : flowEntries) {
987 empty = false;
988 // flowObj.removeFlowEntry(flowEntryObj);
989 // conn.utils().removeFlowEntry(conn, flowEntryObj);
990 flowEntryObj.setUserState("FE_USER_DELETE");
991 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
992 }
993 // Remove from the database empty flows
994 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700995 op.removeFlowPath(flowObj);
996 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800997
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800998 return true;
999 }
1000
1001 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001002 * Clear the state for all previously added flows.
1003 *
1004 * @return true on success, otherwise false.
1005 */
1006 @Override
1007 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001008 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001009
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001010 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001011 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001012 for (IFlowPath flowPathObj : allFlowPaths) {
1013 if (flowPathObj == null)
1014 continue;
1015 String flowIdStr = flowPathObj.getFlowId();
1016 if (flowIdStr == null)
1017 continue;
1018 FlowId flowId = new FlowId(flowIdStr);
1019 allFlowIds.add(flowId);
1020 }
1021
1022 // Clear all flows one-by-one
1023 for (FlowId flowId : allFlowIds) {
1024 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001025 }
1026
1027 return true;
1028 }
1029
1030 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001031 * Clear the state for a previously added flow.
1032 *
1033 * @param flowId the Flow ID of the flow to clear.
1034 * @return true on success, otherwise false.
1035 */
1036 @Override
1037 public boolean clearFlow(FlowId flowId) {
1038 IFlowPath flowObj = null;
1039 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001040 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001041 != null) {
1042 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1043 flowId.toString());
1044 } else {
1045 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1046 flowId.toString());
1047 }
1048 } catch (Exception e) {
1049 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001050 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001051 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1052 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001053 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001054 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001055 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001056 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001057
1058 //
1059 // Remove all Flow Entries
1060 //
1061 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1062 for (IFlowEntry flowEntryObj : flowEntries) {
1063 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001064 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001065 }
1066 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001067 op.removeFlowPath(flowObj);
1068 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001069
1070 return true;
1071 }
1072
1073 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001074 * Get a previously added flow.
1075 *
1076 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001077 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001078 */
1079 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001080 public FlowPath getFlow(FlowId flowId) {
1081 IFlowPath flowObj = null;
1082 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001083 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001084 != null) {
1085 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1086 flowId.toString());
1087 } else {
1088 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1089 flowId.toString());
1090 }
1091 } catch (Exception e) {
1092 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001093 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001094 log.error(":getFlow FlowId:{} failed", flowId.toString());
1095 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001096 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001097 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001098 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001099 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001100
1101 //
1102 // Extract the Flow state
1103 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001104 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001105 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001106
1107 return flowPath;
1108 }
1109
1110 /**
1111 * Get all previously added flows by a specific installer for a given
1112 * data path endpoints.
1113 *
1114 * @param installerId the Caller ID of the installer of the flow to get.
1115 * @param dataPathEndpoints the data path endpoints of the flow to get.
1116 * @return the Flow Paths if found, otherwise null.
1117 */
1118 @Override
1119 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1120 DataPathEndpoints dataPathEndpoints) {
1121 //
1122 // TODO: The implementation below is not optimal:
1123 // We fetch all flows, and then return only the subset that match
1124 // the query conditions.
1125 // We should use the appropriate Titan/Gremlin query to filter-out
1126 // the flows as appropriate.
1127 //
1128 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001129 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001130
1131 if (allFlows == null) {
1132 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001133 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001134 }
1135
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001136 for (FlowPath flow : allFlows) {
1137 //
1138 // TODO: String-based comparison is sub-optimal.
1139 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001140 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001141 //
1142 if (! flow.installerId().toString().equals(installerId.toString()))
1143 continue;
1144 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1145 continue;
1146 }
1147 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1148 continue;
1149 }
1150 flowPaths.add(flow);
1151 }
1152
1153 if (flowPaths.isEmpty()) {
1154 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001155 } else {
1156 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1157 }
1158
1159 return flowPaths;
1160 }
1161
1162 /**
1163 * Get all installed flows by all installers for given data path endpoints.
1164 *
1165 * @param dataPathEndpoints the data path endpoints of the flows to get.
1166 * @return the Flow Paths if found, otherwise null.
1167 */
1168 @Override
1169 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1170 //
1171 // TODO: The implementation below is not optimal:
1172 // We fetch all flows, and then return only the subset that match
1173 // the query conditions.
1174 // We should use the appropriate Titan/Gremlin query to filter-out
1175 // the flows as appropriate.
1176 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001177 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1178 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001179
1180 if (allFlows == null) {
1181 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001182 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001183 }
1184
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001185 for (FlowPath flow : allFlows) {
1186 //
1187 // TODO: String-based comparison is sub-optimal.
1188 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001189 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001190 //
1191 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1192 continue;
1193 }
1194 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1195 continue;
1196 }
1197 flowPaths.add(flow);
1198 }
1199
1200 if (flowPaths.isEmpty()) {
1201 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001202 } else {
1203 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1204 }
1205
1206 return flowPaths;
1207 }
1208
1209 /**
admin944ef4f2013-10-08 17:48:37 -07001210 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001211 *
admin944ef4f2013-10-08 17:48:37 -07001212 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001213 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001214 * @return the Flow Paths if found, otherwise null.
1215 */
1216 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001217 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001218
admin944ef4f2013-10-08 17:48:37 -07001219 //
1220 // TODO: The implementation below is not optimal:
1221 // We fetch all flows, and then return only the subset that match
1222 // the query conditions.
1223 // We should use the appropriate Titan/Gremlin query to filter-out
1224 // the flows as appropriate.
1225 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001226 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001227
Jonathan Hart01f2d272013-04-04 20:03:46 -07001228 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1229
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001230 Collections.sort(flowPathsWithoutFlowEntries,
1231 new Comparator<IFlowPath>(){
1232 @Override
1233 public int compare(IFlowPath first, IFlowPath second) {
1234 // TODO Auto-generated method stub
1235 long result = new FlowId(first.getFlowId()).value()
1236 - new FlowId(second.getFlowId()).value();
1237 if (result > 0) return 1;
1238 else if (result < 0) return -1;
1239 else return 0;
1240 }
1241 }
1242 );
1243
Jonathan Hart01f2d272013-04-04 20:03:46 -07001244 return flowPathsWithoutFlowEntries;
1245
1246 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001247 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001248
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001249 if (allFlows == null) {
1250 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001251 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001252 }
1253
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001254 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001255
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001256 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001257 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001258
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001259 // start from desired flowId
1260 if (flow.flowId().value() < flowId.value()) {
1261 continue;
1262 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001263
1264 // Summarize by making null flow entry fields that are not relevant to report
1265 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1266 flowEntry.setFlowEntryActions(null);
1267 flowEntry.setFlowEntryMatch(null);
1268 }
1269
1270 flowPaths.add(flow);
1271 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1272 break;
1273 }
1274 }
1275
1276 if (flowPaths.isEmpty()) {
1277 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001278 } else {
1279 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1280 }
1281
1282 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001283 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001284 }
1285
1286 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001287 * Get all installed flows by all installers.
1288 *
1289 * @return the Flow Paths if found, otherwise null.
1290 */
1291 @Override
1292 public ArrayList<FlowPath> getAllFlows() {
1293 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001294 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001295
1296 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001297 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001298 log.debug("Get all FlowPaths: found FlowPaths");
1299 } else {
1300 log.debug("Get all FlowPaths: no FlowPaths found");
1301 }
1302 } catch (Exception e) {
1303 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001304 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001305 log.error(":getAllFlowPaths failed");
1306 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001307 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001308 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001309 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001310 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001311
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001312 for (IFlowPath flowObj : flowPathsObj) {
1313 //
1314 // Extract the Flow state
1315 //
1316 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001317 if (flowPath != null)
1318 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001319 }
1320
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001321 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001322
1323 return flowPaths;
1324 }
admin944ef4f2013-10-08 17:48:37 -07001325
1326 /**
1327 * Get all Flows information, without the associated Flow Entries.
1328 *
1329 * @return all Flows information, without the associated Flow Entries.
1330 */
1331 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001332 Iterable<IFlowPath> flowPathsObj = null;
1333 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001334
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001335 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001336
Jonathan Hart01f2d272013-04-04 20:03:46 -07001337 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001338 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001339 log.debug("Get all FlowPaths: found FlowPaths");
1340 } else {
1341 log.debug("Get all FlowPaths: no FlowPaths found");
1342 }
1343 } catch (Exception e) {
1344 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001345 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001346 log.error(":getAllFlowPaths failed");
1347 }
1348 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1349 return new ArrayList<IFlowPath>(); // No Flows found
1350 }
1351
1352 for (IFlowPath flowObj : flowPathsObj){
1353 flowPathsObjArray.add(flowObj);
1354 }
1355 /*
Yuta HIGUCHI1e3eba82013-10-09 17:34:54 -07001356 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001357 for (IFlowPath flowObj : flowPathsObj) {
1358 //
1359 // Extract the Flow state
1360 //
1361 FlowPath flowPath = extractFlowPath(flowObj);
1362 if (flowPath != null)
1363 flowPaths.add(flowPath);
1364 }
1365 */
1366
1367 //conn.endTx(Transaction.COMMIT);
1368
1369 return flowPathsObjArray;
1370 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001371
1372 /**
1373 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1374 *
1375 * @param flowObj the object to extract the Flow Path State from.
1376 * @return the extracted Flow Path State.
1377 */
1378 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001379 //
1380 // Extract the Flow state
1381 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001382 String flowIdStr = flowObj.getFlowId();
1383 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001384 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001385 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001386 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001387 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001388 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001389
1390 if ((flowIdStr == null) ||
1391 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001392 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001393 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001394 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001395 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001396 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001397 // TODO: A work-around, becauuse of some bogus database objects
1398 return null;
1399 }
1400
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001401 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001402 flowPath.setFlowId(new FlowId(flowIdStr));
1403 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001404 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001405 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001406 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001407 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001408 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001409 //
1410 // Extract the match conditions common for all Flow Entries
1411 //
1412 {
1413 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001414 String matchSrcMac = flowObj.getMatchSrcMac();
1415 if (matchSrcMac != null)
1416 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1417 String matchDstMac = flowObj.getMatchDstMac();
1418 if (matchDstMac != null)
1419 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001420 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1421 if (matchEthernetFrameType != null)
1422 match.enableEthernetFrameType(matchEthernetFrameType);
1423 Short matchVlanId = flowObj.getMatchVlanId();
1424 if (matchVlanId != null)
1425 match.enableVlanId(matchVlanId);
1426 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1427 if (matchVlanPriority != null)
1428 match.enableVlanPriority(matchVlanPriority);
1429 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1430 if (matchSrcIPv4Net != null)
1431 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1432 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1433 if (matchDstIPv4Net != null)
1434 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1435 Byte matchIpProto = flowObj.getMatchIpProto();
1436 if (matchIpProto != null)
1437 match.enableIpProto(matchIpProto);
1438 Byte matchIpToS = flowObj.getMatchIpToS();
1439 if (matchIpToS != null)
1440 match.enableIpToS(matchIpToS);
1441 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1442 if (matchSrcTcpUdpPort != null)
1443 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1444 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1445 if (matchDstTcpUdpPort != null)
1446 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1447
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001448 flowPath.setFlowEntryMatch(match);
1449 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001450 //
1451 // Extract the actions for the first Flow Entry
1452 //
1453 {
1454 String actionsStr = flowObj.getActions();
1455 if (actionsStr != null) {
1456 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1457 flowPath.setFlowEntryActions(flowEntryActions);
1458 }
1459 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001460
1461 //
1462 // Extract all Flow Entries
1463 //
1464 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1465 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001466 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1467 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001468 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001469 flowPath.dataPath().flowEntries().add(flowEntry);
1470 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001471
1472 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001473 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001474
1475 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001476 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1477 *
1478 * @param flowEntryObj the object to extract the Flow Entry State from.
1479 * @return the extracted Flow Entry State.
1480 */
1481 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1482 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1483 String switchDpidStr = flowEntryObj.getSwitchDpid();
1484 String userState = flowEntryObj.getUserState();
1485 String switchState = flowEntryObj.getSwitchState();
1486
1487 if ((flowEntryIdStr == null) ||
1488 (switchDpidStr == null) ||
1489 (userState == null) ||
1490 (switchState == null)) {
1491 // TODO: A work-around, becauuse of some bogus database objects
1492 return null;
1493 }
1494
1495 FlowEntry flowEntry = new FlowEntry();
1496 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1497 flowEntry.setDpid(new Dpid(switchDpidStr));
1498
1499 //
1500 // Extract the match conditions
1501 //
1502 FlowEntryMatch match = new FlowEntryMatch();
1503 Short matchInPort = flowEntryObj.getMatchInPort();
1504 if (matchInPort != null)
1505 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001506 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1507 if (matchSrcMac != null)
1508 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1509 String matchDstMac = flowEntryObj.getMatchDstMac();
1510 if (matchDstMac != null)
1511 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001512 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1513 if (matchEthernetFrameType != null)
1514 match.enableEthernetFrameType(matchEthernetFrameType);
1515 Short matchVlanId = flowEntryObj.getMatchVlanId();
1516 if (matchVlanId != null)
1517 match.enableVlanId(matchVlanId);
1518 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1519 if (matchVlanPriority != null)
1520 match.enableVlanPriority(matchVlanPriority);
1521 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1522 if (matchSrcIPv4Net != null)
1523 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1524 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1525 if (matchDstIPv4Net != null)
1526 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1527 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1528 if (matchIpProto != null)
1529 match.enableIpProto(matchIpProto);
1530 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1531 if (matchIpToS != null)
1532 match.enableIpToS(matchIpToS);
1533 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1534 if (matchSrcTcpUdpPort != null)
1535 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1536 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1537 if (matchDstTcpUdpPort != null)
1538 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001539 flowEntry.setFlowEntryMatch(match);
1540
1541 //
1542 // Extract the actions
1543 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001544 FlowEntryActions actions = new FlowEntryActions();
1545 String actionsStr = flowEntryObj.getActions();
1546 if (actionsStr != null)
1547 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001548 flowEntry.setFlowEntryActions(actions);
1549 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1550 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1551 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001552 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001553 //
1554 return flowEntry;
1555 }
1556
1557 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001558 * Add and maintain a shortest-path flow.
1559 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001560 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001561 *
1562 * @param flowPath the Flow Path with the endpoints and the match
1563 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001564 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001565 */
1566 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001567 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001568 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001569 // Don't do the shortest path computation here.
1570 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001571 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001572
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001573 // We need the DataPath to populate the Network MAP
1574 DataPath dataPath = new DataPath();
1575 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1576 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001577
1578 //
1579 // Prepare the computed Flow Path
1580 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001581 FlowPath computedFlowPath = new FlowPath();
1582 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1583 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001584 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001585 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001586 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001587 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001588
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001589 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001590 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001591 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001592 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001593
1594 // TODO: Mark the flow for maintenance purpose
1595
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001596 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001597 }
1598
1599 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001600 * Reconcile a flow.
1601 *
1602 * @param flowObj the flow that needs to be reconciliated.
1603 * @param newDataPath the new data path to use.
1604 * @return true on success, otherwise false.
1605 */
1606 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001607
1608 //
1609 // Set the incoming port matching and the outgoing port output
1610 // actions for each flow entry.
1611 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001612 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001613 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1614 // Set the incoming port matching
1615 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1616 flowEntry.setFlowEntryMatch(flowEntryMatch);
1617 flowEntryMatch.enableInPort(flowEntry.inPort());
1618
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001619 //
1620 // Set the actions
1621 //
1622 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1623 //
1624 // If the first Flow Entry, copy the Flow Path actions to it
1625 //
1626 if (idx == 0) {
1627 String actionsStr = flowObj.getActions();
1628 if (actionsStr != null) {
1629 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1630 for (FlowEntryAction action : flowActions.actions())
1631 flowEntryActions.addAction(action);
1632 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001633 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001634 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001635 //
1636 // Add the outgoing port output action
1637 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001638 FlowEntryAction flowEntryAction = new FlowEntryAction();
1639 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001640 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001641 }
1642
1643 //
1644 // Remove the old Flow Entries, and add the new Flow Entries
1645 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001646 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001647 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001648 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001649 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001650 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001651 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001652 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001653 }
1654
1655 //
1656 // Set the Data Path Summary
1657 //
1658 String dataPathSummaryStr = newDataPath.dataPathSummary();
1659 flowObj.setDataPathSummary(dataPathSummaryStr);
1660
1661 return true;
1662 }
1663
1664 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001665 * Reconcile all flows in a set.
1666 *
1667 * @param flowObjSet the set of flows that need to be reconciliated.
1668 */
1669 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1670 if (! flowObjSet.iterator().hasNext())
1671 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001672 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673 }
1674
1675 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001676 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001677 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001678 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001679 * @param flowObj the flow path object for the flow entry to install.
1680 * @param flowEntryObj the flow entry object to install.
1681 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001682 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001683 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1684 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001685 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1686 if (flowEntryIdStr == null)
1687 return false;
1688 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001689 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001690 if (userState == null)
1691 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001692
1693 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001694 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001695 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001696 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1697 .getMessage(OFType.FLOW_MOD);
1698 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001699
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001700 short flowModCommand = OFFlowMod.OFPFC_ADD;
1701 if (userState.equals("FE_USER_ADD")) {
1702 flowModCommand = OFFlowMod.OFPFC_ADD;
1703 } else if (userState.equals("FE_USER_MODIFY")) {
1704 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1705 } else if (userState.equals("FE_USER_DELETE")) {
1706 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1707 } else {
1708 // Unknown user state. Ignore the entry
1709 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1710 flowEntryId.toString(), userState);
1711 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001712 }
1713
1714 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001715 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001716 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001717 // NOTE: The Flow matching conditions common for all Flow Entries are
1718 // used ONLY if a Flow Entry does NOT have the corresponding matching
1719 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001720 //
1721 OFMatch match = new OFMatch();
1722 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001723
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001724 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001725 Short matchInPort = flowEntryObj.getMatchInPort();
1726 if (matchInPort != null) {
1727 match.setInputPort(matchInPort);
1728 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1729 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001730
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001731 // Match the Source MAC address
1732 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1733 if (matchSrcMac == null)
1734 matchSrcMac = flowObj.getMatchSrcMac();
1735 if (matchSrcMac != null) {
1736 match.setDataLayerSource(matchSrcMac);
1737 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1738 }
1739
1740 // Match the Destination MAC address
1741 String matchDstMac = flowEntryObj.getMatchDstMac();
1742 if (matchDstMac == null)
1743 matchDstMac = flowObj.getMatchDstMac();
1744 if (matchDstMac != null) {
1745 match.setDataLayerDestination(matchDstMac);
1746 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1747 }
1748
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001749 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001750 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1751 if (matchEthernetFrameType == null)
1752 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1753 if (matchEthernetFrameType != null) {
1754 match.setDataLayerType(matchEthernetFrameType);
1755 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1756 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001757
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001758 // Match the VLAN ID
1759 Short matchVlanId = flowEntryObj.getMatchVlanId();
1760 if (matchVlanId == null)
1761 matchVlanId = flowObj.getMatchVlanId();
1762 if (matchVlanId != null) {
1763 match.setDataLayerVirtualLan(matchVlanId);
1764 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1765 }
1766
1767 // Match the VLAN priority
1768 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1769 if (matchVlanPriority == null)
1770 matchVlanPriority = flowObj.getMatchVlanPriority();
1771 if (matchVlanPriority != null) {
1772 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1773 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1774 }
1775
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001776 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001777 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1778 if (matchSrcIPv4Net == null)
1779 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1780 if (matchSrcIPv4Net != null) {
1781 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1782 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001783
1784 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001785 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1786 if (matchDstIPv4Net == null)
1787 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1788 if (matchDstIPv4Net != null) {
1789 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1790 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001791
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001792 // Match the IP protocol
1793 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1794 if (matchIpProto == null)
1795 matchIpProto = flowObj.getMatchIpProto();
1796 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001797 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001798 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001799 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001800
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001801 // Match the IP ToS (DSCP field, 6 bits)
1802 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1803 if (matchIpToS == null)
1804 matchIpToS = flowObj.getMatchIpToS();
1805 if (matchIpToS != null) {
1806 match.setNetworkTypeOfService(matchIpToS);
1807 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1808 }
1809
1810 // Match the Source TCP/UDP port
1811 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1812 if (matchSrcTcpUdpPort == null)
1813 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1814 if (matchSrcTcpUdpPort != null) {
1815 match.setTransportSource(matchSrcTcpUdpPort);
1816 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1817 }
1818
1819 // Match the Destination TCP/UDP port
1820 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1821 if (matchDstTcpUdpPort == null)
1822 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1823 if (matchDstTcpUdpPort != null) {
1824 match.setTransportDestination(matchDstTcpUdpPort);
1825 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001826 }
1827
1828 //
1829 // Fetch the actions
1830 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001831 Short actionOutputPort = null;
1832 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1833 int actionsLen = 0;
1834 FlowEntryActions flowEntryActions = null;
1835 String actionsStr = flowEntryObj.getActions();
1836 if (actionsStr != null)
1837 flowEntryActions = new FlowEntryActions(actionsStr);
1838 for (FlowEntryAction action : flowEntryActions.actions()) {
1839 ActionOutput actionOutput = action.actionOutput();
1840 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1841 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1842 ActionStripVlan actionStripVlan = action.actionStripVlan();
1843 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1844 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1845 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1846 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1847 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1848 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1849 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1850 ActionEnqueue actionEnqueue = action.actionEnqueue();
1851
1852 if (actionOutput != null) {
1853 actionOutputPort = actionOutput.port().value();
1854 // XXX: The max length is hard-coded for now
1855 OFActionOutput ofa =
1856 new OFActionOutput(actionOutput.port().value(),
1857 (short)0xffff);
1858 openFlowActions.add(ofa);
1859 actionsLen += ofa.getLength();
1860 }
1861
1862 if (actionSetVlanId != null) {
1863 OFActionVirtualLanIdentifier ofa =
1864 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1865 openFlowActions.add(ofa);
1866 actionsLen += ofa.getLength();
1867 }
1868
1869 if (actionSetVlanPriority != null) {
1870 OFActionVirtualLanPriorityCodePoint ofa =
1871 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1872 openFlowActions.add(ofa);
1873 actionsLen += ofa.getLength();
1874 }
1875
1876 if (actionStripVlan != null) {
1877 if (actionStripVlan.stripVlan() == true) {
1878 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1879 openFlowActions.add(ofa);
1880 actionsLen += ofa.getLength();
1881 }
1882 }
1883
1884 if (actionSetEthernetSrcAddr != null) {
1885 OFActionDataLayerSource ofa =
1886 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1887 openFlowActions.add(ofa);
1888 actionsLen += ofa.getLength();
1889 }
1890
1891 if (actionSetEthernetDstAddr != null) {
1892 OFActionDataLayerDestination ofa =
1893 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1894 openFlowActions.add(ofa);
1895 actionsLen += ofa.getLength();
1896 }
1897
1898 if (actionSetIPv4SrcAddr != null) {
1899 OFActionNetworkLayerSource ofa =
1900 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1901 openFlowActions.add(ofa);
1902 actionsLen += ofa.getLength();
1903 }
1904
1905 if (actionSetIPv4DstAddr != null) {
1906 OFActionNetworkLayerDestination ofa =
1907 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1908 openFlowActions.add(ofa);
1909 actionsLen += ofa.getLength();
1910 }
1911
1912 if (actionSetIpToS != null) {
1913 OFActionNetworkTypeOfService ofa =
1914 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1915 openFlowActions.add(ofa);
1916 actionsLen += ofa.getLength();
1917 }
1918
1919 if (actionSetTcpUdpSrcPort != null) {
1920 OFActionTransportLayerSource ofa =
1921 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1922 openFlowActions.add(ofa);
1923 actionsLen += ofa.getLength();
1924 }
1925
1926 if (actionSetTcpUdpDstPort != null) {
1927 OFActionTransportLayerDestination ofa =
1928 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1929 openFlowActions.add(ofa);
1930 actionsLen += ofa.getLength();
1931 }
1932
1933 if (actionEnqueue != null) {
1934 OFActionEnqueue ofa =
1935 new OFActionEnqueue(actionEnqueue.port().value(),
1936 actionEnqueue.queueId());
1937 openFlowActions.add(ofa);
1938 actionsLen += ofa.getLength();
1939 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001940 }
1941
1942 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1943 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1944 .setPriority(PRIORITY_DEFAULT)
1945 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1946 .setCookie(cookie)
1947 .setCommand(flowModCommand)
1948 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001949 .setActions(openFlowActions)
1950 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001951 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1952 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1953 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1954 if (actionOutputPort != null)
1955 fm.setOutPort(actionOutputPort);
1956 }
1957
1958 //
1959 // TODO: Set the following flag
1960 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1961 // See method ForwardingBase::pushRoute()
1962 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001963
1964 //
1965 // Write the message to the switch
1966 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001967 log.debug("MEASUREMENT: Installing flow entry " + userState +
1968 " into switch DPID: " +
1969 mySwitch.getStringId() +
1970 " flowEntryId: " + flowEntryId.toString() +
1971 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1972 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1973 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001974 try {
1975 messageDamper.write(mySwitch, fm, null);
1976 mySwitch.flush();
1977 //
1978 // TODO: We should use the OpenFlow Barrier mechanism
1979 // to check for errors, and update the SwitchState
1980 // for a flow entry after the Barrier message is
1981 // is received.
1982 //
1983 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1984 } catch (IOException e) {
1985 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001986 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001987 }
1988
1989 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001990 }
1991
1992 /**
1993 * Install a Flow Entry on a switch.
1994 *
1995 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001996 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001997 * @param flowEntry the flow entry to install.
1998 * @return true on success, otherwise false.
1999 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002000 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2001 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002002 //
2003 // Create the OpenFlow Flow Modification Entry to push
2004 //
2005 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
2006 .getMessage(OFType.FLOW_MOD);
2007 long cookie = flowEntry.flowEntryId().value();
2008
2009 short flowModCommand = OFFlowMod.OFPFC_ADD;
2010 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
2011 flowModCommand = OFFlowMod.OFPFC_ADD;
2012 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
2013 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
2014 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
2015 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
2016 } else {
2017 // Unknown user state. Ignore the entry
2018 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
2019 flowEntry.flowEntryId().toString(),
2020 flowEntry.flowEntryUserState());
2021 return false;
2022 }
2023
2024 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002025 // Fetch the match conditions.
2026 //
2027 // NOTE: The Flow matching conditions common for all Flow Entries are
2028 // used ONLY if a Flow Entry does NOT have the corresponding matching
2029 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002030 //
2031 OFMatch match = new OFMatch();
2032 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002033 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
2034 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
2035
2036 // Match the Incoming Port
2037 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002038 if (matchInPort != null) {
2039 match.setInputPort(matchInPort.value());
2040 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
2041 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002042
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002043 // Match the Source MAC address
2044 MACAddress matchSrcMac = flowEntryMatch.srcMac();
2045 if ((matchSrcMac == null) && (flowPathMatch != null)) {
2046 matchSrcMac = flowPathMatch.srcMac();
2047 }
2048 if (matchSrcMac != null) {
2049 match.setDataLayerSource(matchSrcMac.toString());
2050 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2051 }
2052
2053 // Match the Destination MAC address
2054 MACAddress matchDstMac = flowEntryMatch.dstMac();
2055 if ((matchDstMac == null) && (flowPathMatch != null)) {
2056 matchDstMac = flowPathMatch.dstMac();
2057 }
2058 if (matchDstMac != null) {
2059 match.setDataLayerDestination(matchDstMac.toString());
2060 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2061 }
2062
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002063 // Match the Ethernet Frame Type
2064 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2065 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2066 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2067 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002068 if (matchEthernetFrameType != null) {
2069 match.setDataLayerType(matchEthernetFrameType);
2070 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2071 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002072
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002073 // Match the VLAN ID
2074 Short matchVlanId = flowEntryMatch.vlanId();
2075 if ((matchVlanId == null) && (flowPathMatch != null)) {
2076 matchVlanId = flowPathMatch.vlanId();
2077 }
2078 if (matchVlanId != null) {
2079 match.setDataLayerVirtualLan(matchVlanId);
2080 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2081 }
2082
2083 // Match the VLAN priority
2084 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2085 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2086 matchVlanPriority = flowPathMatch.vlanPriority();
2087 }
2088 if (matchVlanPriority != null) {
2089 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2090 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2091 }
2092
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002093 // Match the Source IPv4 Network prefix
2094 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2095 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2096 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2097 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002098 if (matchSrcIPv4Net != null) {
2099 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2100 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002101
2102 // Natch the Destination IPv4 Network prefix
2103 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2104 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2105 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2106 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002107 if (matchDstIPv4Net != null) {
2108 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2109 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002110
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002111 // Match the IP protocol
2112 Byte matchIpProto = flowEntryMatch.ipProto();
2113 if ((matchIpProto == null) && (flowPathMatch != null)) {
2114 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002115 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002116 if (matchIpProto != null) {
2117 match.setNetworkProtocol(matchIpProto);
2118 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002119 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002120
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002121 // Match the IP ToS (DSCP field, 6 bits)
2122 Byte matchIpToS = flowEntryMatch.ipToS();
2123 if ((matchIpToS == null) && (flowPathMatch != null)) {
2124 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002125 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002126 if (matchIpToS != null) {
2127 match.setNetworkTypeOfService(matchIpToS);
2128 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2129 }
2130
2131 // Match the Source TCP/UDP port
2132 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2133 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2134 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2135 }
2136 if (matchSrcTcpUdpPort != null) {
2137 match.setTransportSource(matchSrcTcpUdpPort);
2138 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2139 }
2140
2141 // Match the Destination TCP/UDP port
2142 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2143 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2144 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2145 }
2146 if (matchDstTcpUdpPort != null) {
2147 match.setTransportDestination(matchDstTcpUdpPort);
2148 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002149 }
2150
2151 //
2152 // Fetch the actions
2153 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002154 Short actionOutputPort = null;
2155 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2156 int actionsLen = 0;
2157 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002158 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002159 for (FlowEntryAction action : flowEntryActions.actions()) {
2160 ActionOutput actionOutput = action.actionOutput();
2161 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2162 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2163 ActionStripVlan actionStripVlan = action.actionStripVlan();
2164 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2165 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2166 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2167 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2168 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2169 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2170 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2171 ActionEnqueue actionEnqueue = action.actionEnqueue();
2172
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002173 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002174 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002175 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002176 OFActionOutput ofa =
2177 new OFActionOutput(actionOutput.port().value(),
2178 (short)0xffff);
2179 openFlowActions.add(ofa);
2180 actionsLen += ofa.getLength();
2181 }
2182
2183 if (actionSetVlanId != null) {
2184 OFActionVirtualLanIdentifier ofa =
2185 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2186 openFlowActions.add(ofa);
2187 actionsLen += ofa.getLength();
2188 }
2189
2190 if (actionSetVlanPriority != null) {
2191 OFActionVirtualLanPriorityCodePoint ofa =
2192 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2193 openFlowActions.add(ofa);
2194 actionsLen += ofa.getLength();
2195 }
2196
2197 if (actionStripVlan != null) {
2198 if (actionStripVlan.stripVlan() == true) {
2199 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2200 openFlowActions.add(ofa);
2201 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002202 }
2203 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002204
2205 if (actionSetEthernetSrcAddr != null) {
2206 OFActionDataLayerSource ofa =
2207 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2208 openFlowActions.add(ofa);
2209 actionsLen += ofa.getLength();
2210 }
2211
2212 if (actionSetEthernetDstAddr != null) {
2213 OFActionDataLayerDestination ofa =
2214 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2215 openFlowActions.add(ofa);
2216 actionsLen += ofa.getLength();
2217 }
2218
2219 if (actionSetIPv4SrcAddr != null) {
2220 OFActionNetworkLayerSource ofa =
2221 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2222 openFlowActions.add(ofa);
2223 actionsLen += ofa.getLength();
2224 }
2225
2226 if (actionSetIPv4DstAddr != null) {
2227 OFActionNetworkLayerDestination ofa =
2228 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2229 openFlowActions.add(ofa);
2230 actionsLen += ofa.getLength();
2231 }
2232
2233 if (actionSetIpToS != null) {
2234 OFActionNetworkTypeOfService ofa =
2235 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2236 openFlowActions.add(ofa);
2237 actionsLen += ofa.getLength();
2238 }
2239
2240 if (actionSetTcpUdpSrcPort != null) {
2241 OFActionTransportLayerSource ofa =
2242 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2243 openFlowActions.add(ofa);
2244 actionsLen += ofa.getLength();
2245 }
2246
2247 if (actionSetTcpUdpDstPort != null) {
2248 OFActionTransportLayerDestination ofa =
2249 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2250 openFlowActions.add(ofa);
2251 actionsLen += ofa.getLength();
2252 }
2253
2254 if (actionEnqueue != null) {
2255 OFActionEnqueue ofa =
2256 new OFActionEnqueue(actionEnqueue.port().value(),
2257 actionEnqueue.queueId());
2258 openFlowActions.add(ofa);
2259 actionsLen += ofa.getLength();
2260 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002261 }
2262
2263 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2264 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2265 .setPriority(PRIORITY_DEFAULT)
2266 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2267 .setCookie(cookie)
2268 .setCommand(flowModCommand)
2269 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002270 .setActions(openFlowActions)
2271 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2272 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2273 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2274 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2275 if (actionOutputPort != null)
2276 fm.setOutPort(actionOutputPort);
2277 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002278
2279 //
2280 // TODO: Set the following flag
2281 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2282 // See method ForwardingBase::pushRoute()
2283 //
2284
2285 //
2286 // Write the message to the switch
2287 //
2288 try {
2289 messageDamper.write(mySwitch, fm, null);
2290 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002291 //
2292 // TODO: We should use the OpenFlow Barrier mechanism
2293 // to check for errors, and update the SwitchState
2294 // for a flow entry after the Barrier message is
2295 // is received.
2296 //
2297 // TODO: The FlowEntry Object in Titan should be set
2298 // to FE_SWITCH_UPDATED.
2299 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002300 } catch (IOException e) {
2301 log.error("Failure writing flow mod from network map", e);
2302 return false;
2303 }
2304 return true;
2305 }
2306
2307 /**
2308 * Remove a Flow Entry from a switch.
2309 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002310 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002311 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002312 * @param flowEntry the flow entry to remove.
2313 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002314 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002315 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2316 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002317 //
2318 // The installFlowEntry() method implements both installation
2319 // and removal of flow entries.
2320 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002321 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002322 }
2323
2324 /**
2325 * Install a Flow Entry on a remote controller.
2326 *
2327 * TODO: We need it now: Jono
2328 * - For now it will make a REST call to the remote controller.
2329 * - Internally, it needs to know the name of the remote controller.
2330 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002331 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002332 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002333 * @return true on success, otherwise false.
2334 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002335 public boolean installRemoteFlowEntry(FlowPath flowPath,
2336 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002337 // TODO: We need it now: Jono
2338 // - For now it will make a REST call to the remote controller.
2339 // - Internally, it needs to know the name of the remote controller.
2340 return true;
2341 }
2342
2343 /**
2344 * Remove a flow entry on a remote controller.
2345 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002346 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002347 * @param flowEntry the flow entry to remove.
2348 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002349 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002350 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2351 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002352 //
2353 // The installRemoteFlowEntry() method implements both installation
2354 // and removal of flow entries.
2355 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002356 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002357 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002358}