blob: 1215558b9e01a410ecde6e7770a4930e2d40c65a [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;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070030
31import net.onrc.onos.datagrid.IDatagridService;
Pankaj Berde38646d62013-06-21 11:34:04 -070032import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070033import net.onrc.onos.ofcontroller.core.INetMapStorage;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
36import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
37import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -070038import net.onrc.onos.ofcontroller.floodlightlistener.INetworkGraphService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070039import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070040import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavov15954d42013-10-19 15:29:04 -070041import net.onrc.onos.ofcontroller.topology.Topology;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070042import net.onrc.onos.ofcontroller.topology.TopologyManager;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070043import net.onrc.onos.ofcontroller.util.CallerId;
44import net.onrc.onos.ofcontroller.util.DataPath;
45import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
46import net.onrc.onos.ofcontroller.util.Dpid;
47import net.onrc.onos.ofcontroller.util.FlowEntry;
48import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070049import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
50import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070051import net.onrc.onos.ofcontroller.util.FlowEntryId;
52import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
53import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
54import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
55import net.onrc.onos.ofcontroller.util.FlowId;
56import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070057import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070058import net.onrc.onos.ofcontroller.util.IPv4Net;
59import net.onrc.onos.ofcontroller.util.Port;
60import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080061
62import org.openflow.protocol.OFFlowMod;
63import org.openflow.protocol.OFMatch;
64import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070065import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080066import org.openflow.protocol.OFType;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070067import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080068import org.slf4j.Logger;
69import org.slf4j.LoggerFactory;
70
admin944ef4f2013-10-08 17:48:37 -070071/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070072 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070073 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070074public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075
Toshio Koide9fe1cb22013-06-13 13:51:11 -070076 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080077
Jonathan Hart50a94982013-04-10 14:49:51 -070078 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070079 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov05378272013-10-19 23:23:05 -070080 protected volatile IDatagridService datagridService;
81 protected IRestApiService restApi;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070082 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080083
84 protected OFMessageDamper messageDamper;
85
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070086 //
87 // TODO: Values copied from elsewhere (class LearningSwitch).
88 // The local copy should go away!
89 //
90 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
91 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
92 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
93 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
94 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080095
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000096 // Flow Entry ID generation state
97 private static Random randomGenerator = new Random();
98 private static int nextFlowEntryIdPrefix = 0;
99 private static int nextFlowEntryIdSuffix = 0;
100 private static long nextFlowEntryId = 0;
101
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700102 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700103 private static long measurementFlowId = 100000;
104 private static String measurementFlowIdStr = "0x186a0"; // 100000
105 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700106 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700107
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800108 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800109 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
110
111 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700112 private ScheduledExecutorService mapReaderScheduler;
113 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700114
admin944ef4f2013-10-08 17:48:37 -0700115 /**
116 * Periodic task for reading the Flow Entries and pushing changes
117 * into the switches.
118 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700119 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800120 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700121 try {
122 runImpl();
123 } catch (Exception e) {
124 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700125 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700126 return;
127 }
128 }
129
130 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700131 long startTime = System.nanoTime();
132 int counterAllFlowEntries = 0;
133 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700134
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800135 if (floodlightProvider == null) {
136 log.debug("FloodlightProvider service not found!");
137 return;
138 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139 Map<Long, IOFSwitch> mySwitches =
140 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700141 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700142 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700143 return;
144 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700145 LinkedList<IFlowEntry> addFlowEntries =
146 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000147 LinkedList<IFlowEntry> deleteFlowEntries =
148 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700149
150 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700151 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700152 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700153 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700154 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000155 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700156 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700157 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700158 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000159
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000160 String dpidStr = flowEntryObj.getSwitchDpid();
161 if (dpidStr == null)
162 continue;
163 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800164 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000165 if (mySwitch == null)
166 continue; // Ignore the entry: not my switch
167
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700168 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700169 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700170 if (flowObj == null)
171 continue; // Should NOT happen
172 if (flowObj.getFlowId() == null)
173 continue; // Invalid entry
174
175 //
176 // NOTE: For now we process the DELETE before the ADD
177 // to cover the more common scenario.
178 // TODO: This is error prone and needs to be fixed!
179 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000180 String userState = flowEntryObj.getUserState();
181 if (userState == null)
182 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700183 if (userState.equals("FE_USER_DELETE")) {
184 // An entry that needs to be deleted.
185 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700186 installFlowEntry(mySwitch, flowObj, flowEntryObj);
187 } else {
188 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700189 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700190 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700191 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700192 // TODO: Commented-out for now
193 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700194 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700195 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700196 processed_measurement_flow = true;
197 }
198 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700199 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700200 }
201
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700202 //
203 // Process the Flow Entries that need to be added
204 //
205 for (IFlowEntry flowEntryObj : addFlowEntries) {
206 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700207 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700208 if (flowObj == null)
209 continue; // Should NOT happen
210 if (flowObj.getFlowId() == null)
211 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700212
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700213 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700214 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000215 if (mySwitch == null)
216 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700217 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800218 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219
220 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000221 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700222 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000223 //
224 // TODO: We should use the OpenFlow Barrier mechanism
225 // to check for errors, and delete the Flow Entries after the
226 // Barrier message is received.
227 //
228 while (! deleteFlowEntries.isEmpty()) {
229 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
230 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700231 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000232 if (flowObj == null) {
233 log.debug("Did not find FlowPath to be deleted");
234 continue;
235 }
236 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700237 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000238 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700239
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700240 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700241
242 if (processed_measurement_flow) {
243 long estimatedTime =
244 System.nanoTime() - modifiedMeasurementFlowTime;
245 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
246 (double)estimatedTime / 1000000000 + " sec";
247 log.debug(logMsg);
248 }
249
250 long estimatedTime = System.nanoTime() - startTime;
251 double rate = 0.0;
252 if (estimatedTime > 0)
253 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
254 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
255 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
256 counterMyNotUpdatedFlowEntries + " in " +
257 (double)estimatedTime / 1000000000 + " sec: " +
258 rate + " paths/s";
259 log.debug(logMsg);
260 }
261 };
262
admin944ef4f2013-10-08 17:48:37 -0700263 /**
264 * Periodic task for reading the Flow Paths and recomputing the
265 * shortest paths.
266 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700267 final Runnable shortestPathReconcile = new Runnable() {
268 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700269 try {
270 runImpl();
271 } catch (Exception e) {
272 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700273 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700274 return;
275 }
276 }
277
278 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700279 long startTime = System.nanoTime();
280 int counterAllFlowPaths = 0;
281 int counterMyFlowPaths = 0;
282
283 if (floodlightProvider == null) {
284 log.debug("FloodlightProvider service not found!");
285 return;
286 }
287 Map<Long, IOFSwitch> mySwitches =
288 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700289 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700290 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700291 return;
292 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700293 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
294
295 boolean processed_measurement_flow = false;
296
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700297 //
298 // Fetch and recompute the Shortest Path for those
299 // Flow Paths this controller is responsible for.
300 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700301 Topology topology = topologyNetService.newDatabaseTopology();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700302 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700303 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700304 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700305 if (flowPathObj == null)
306 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700308 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000309 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700310 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700311 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700312 //
313 // Use the source DPID as a heuristic to decide
314 // which controller is responsible for maintaining the
315 // shortest path.
316 // NOTE: This heuristic is error-prone: if the switch
317 // goes away and no controller is responsible for that
318 // switch, then the original Flow Path is not cleaned-up
319 //
320 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
321 if (mySwitch == null)
322 continue; // Ignore: not my responsibility
323
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700324 // Test the Data Path Summary string
325 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
326 if (dataPathSummaryStr == null)
327 continue; // Could be invalid entry?
328 if (dataPathSummaryStr.isEmpty())
329 continue; // No need to maintain this flow
330
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000331 //
332 // Test whether we need to complete the Flow cleanup,
333 // if the Flow has been deleted by the user.
334 //
335 String flowUserState = flowPathObj.getUserState();
336 if ((flowUserState != null)
337 && flowUserState.equals("FE_USER_DELETE")) {
338 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700339 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000340 if (empty)
341 deleteFlows.add(flowPathObj);
342 }
343
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000344 // Fetch the fields needed to recompute the shortest path
345 Short srcPortShort = flowPathObj.getSrcPort();
346 String dstDpidStr = flowPathObj.getDstSwitch();
347 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700348 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000349 if ((srcPortShort == null) ||
350 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700351 (dstPortShort == null) ||
352 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000353 continue;
354 }
355
356 Port srcPort = new Port(srcPortShort);
357 Dpid dstDpid = new Dpid(dstDpidStr);
358 Port dstPort = new Port(dstPortShort);
359 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
360 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700361 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000362
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700363 counterMyFlowPaths++;
364
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700365 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700366 // NOTE: Using here the regular getDatabaseShortestPath()
367 // method won't work here, because that method calls
368 // internally "conn.endTx(Transaction.COMMIT)", and that
369 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700370 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700371 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700372 // to avoid closing the transaction.
373 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700374 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700375 topologyNetService.getTopologyShortestPath(
376 topology,
377 srcSwitchPort,
378 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000379 if (dataPath == null) {
380 // We need the DataPath to compare the paths
381 dataPath = new DataPath();
382 dataPath.setSrcPort(srcSwitchPort);
383 dataPath.setDstPort(dstSwitchPort);
384 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700385 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000386
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700387 String newDataPathSummaryStr = dataPath.dataPathSummary();
388 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
389 continue; // Nothing changed
390
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700391 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700392 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000393
394 //
395 // Delete all leftover Flows marked for deletion from the
396 // Network MAP.
397 //
398 while (! deleteFlows.isEmpty()) {
399 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700400 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000401 }
402
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700403 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700404
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700405 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700406
407 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700408 long estimatedTime =
409 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700410 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
411 (double)estimatedTime / 1000000000 + " sec";
412 log.debug(logMsg);
413 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700414
415 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700416 double rate = 0.0;
417 if (estimatedTime > 0)
418 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700419 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700420 counterAllFlowPaths + " MyFlowPaths: " +
421 counterMyFlowPaths + " in " +
422 (double)estimatedTime / 1000000000 + " sec: " +
423 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700424 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425 }
426 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700427
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428
admin944ef4f2013-10-08 17:48:37 -0700429 /**
430 * Initialize the Flow Manager.
431 *
432 * @param conf the Graph Database configuration string.
433 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800434 @Override
435 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700436 op = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800437 }
438
admin944ef4f2013-10-08 17:48:37 -0700439 /**
440 * Shutdown the Flow Manager operation.
441 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800442 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700443 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800444 }
445
admin944ef4f2013-10-08 17:48:37 -0700446 /**
447 * Shutdown the Flow Manager operation.
448 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800449 @Override
450 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700451 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453
admin944ef4f2013-10-08 17:48:37 -0700454 /**
455 * Get the collection of offered module services.
456 *
457 * @return the collection of offered module services.
458 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800459 @Override
460 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
461 Collection<Class<? extends IFloodlightService>> l =
462 new ArrayList<Class<? extends IFloodlightService>>();
463 l.add(IFlowService.class);
464 return l;
465 }
466
admin944ef4f2013-10-08 17:48:37 -0700467 /**
468 * Get the collection of implemented services.
469 *
470 * @return the collection of implemented services.
471 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800472 @Override
473 public Map<Class<? extends IFloodlightService>, IFloodlightService>
474 getServiceImpls() {
475 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700476 IFloodlightService> m =
477 new HashMap<Class<? extends IFloodlightService>,
478 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800479 m.put(IFlowService.class, this);
480 return m;
481 }
482
admin944ef4f2013-10-08 17:48:37 -0700483 /**
484 * Get the collection of modules this module depends on.
485 *
486 * @return the collection of modules this module depends on.
487 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488 @Override
489 public Collection<Class<? extends IFloodlightService>>
490 getModuleDependencies() {
491 Collection<Class<? extends IFloodlightService>> l =
492 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800493 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700494 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700495 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800496 l.add(IRestApiService.class);
497 return l;
498 }
499
admin944ef4f2013-10-08 17:48:37 -0700500 /**
501 * Initialize the module.
502 *
503 * @param context the module context to use for the initialization.
504 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800505 @Override
506 public void init(FloodlightModuleContext context)
507 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700508 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700510 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
511 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800512 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700513
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800514 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
515 EnumSet.of(OFType.FLOW_MOD),
516 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700517
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700518 String conf = "";
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800519 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700520
admin944ef4f2013-10-08 17:48:37 -0700521 mapReaderScheduler = Executors.newScheduledThreadPool(1);
522 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800523 }
524
admin944ef4f2013-10-08 17:48:37 -0700525 /**
526 * Get the next Flow Entry ID to use.
527 *
528 * @return the next Flow Entry ID to use.
529 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700530 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000531 //
532 // Generate the next Flow Entry ID.
533 // NOTE: For now, the higher 32 bits are random, and
534 // the lower 32 bits are sequential.
535 // In the future, we need a better allocation mechanism.
536 //
537 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
538 nextFlowEntryIdPrefix = randomGenerator.nextInt();
539 nextFlowEntryIdSuffix = 0;
540 } else {
541 nextFlowEntryIdSuffix++;
542 }
543 long result = (long)nextFlowEntryIdPrefix << 32;
544 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
545 return result;
546 }
547
admin944ef4f2013-10-08 17:48:37 -0700548 /**
549 * Startup module operation.
550 *
551 * @param context the module context to use for the startup.
552 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800553 @Override
554 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700555 restApi.addRestletRoutable(new FlowWebRoutable());
Jonathan Hart50a94982013-04-10 14:49:51 -0700556
admin944ef4f2013-10-08 17:48:37 -0700557 // Initialize the Flow Entry ID generator
558 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Jonathan Hart50a94982013-04-10 14:49:51 -0700559
admin944ef4f2013-10-08 17:48:37 -0700560 mapReaderScheduler.scheduleAtFixedRate(
561 mapReader, 3, 3, TimeUnit.SECONDS);
562 shortestPathReconcileScheduler.scheduleAtFixedRate(
563 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800564 }
565
566 /**
567 * Add a flow.
568 *
569 * Internally, ONOS will automatically register the installer for
570 * receiving Flow Path Notifications for that path.
571 *
572 * @param flowPath the Flow Path to install.
573 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700574 * @param dataPathSummaryStr the data path summary string if the added
575 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800576 * @return true on success, otherwise false.
577 */
578 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700579 public boolean addFlow(FlowPath flowPath, FlowId flowId,
580 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700581 /*
582 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700583 if (flowPath.flowId().value() == measurementFlowId) {
584 modifiedMeasurementFlowTime = System.nanoTime();
585 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700586 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800587
588 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000589 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800590 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700591 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800592 != null) {
593 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
594 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000595 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800596 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700597 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800598 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
599 flowPath.flowId().toString());
600 }
601 } catch (Exception e) {
602 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700603 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000604
605 StringWriter sw = new StringWriter();
606 e.printStackTrace(new PrintWriter(sw));
607 String stacktrace = sw.toString();
608
609 log.error(":addFlow FlowId:{} failed: {}",
610 flowPath.flowId().toString(),
611 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800612 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700613 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000614 log.error(":addFlow FlowId:{} failed: Flow object not created",
615 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700616 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800617 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700618 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800619
620 //
621 // Set the Flow key:
622 // - flowId
623 //
624 flowObj.setFlowId(flowPath.flowId().toString());
625 flowObj.setType("flow");
626
627 //
628 // Set the Flow attributes:
629 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700630 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800631 // - flowPath.dataPath().srcPort()
632 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700633 // - flowPath.matchSrcMac()
634 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700635 // - flowPath.matchEthernetFrameType()
636 // - flowPath.matchVlanId()
637 // - flowPath.matchVlanPriority()
638 // - flowPath.matchSrcIPv4Net()
639 // - flowPath.matchDstIPv4Net()
640 // - flowPath.matchIpProto()
641 // - flowPath.matchIpToS()
642 // - flowPath.matchSrcTcpUdpPort()
643 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700644 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800645 //
646 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700647 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800648 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
649 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
650 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
651 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700652 if (flowPath.flowEntryMatch().matchSrcMac()) {
653 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
654 }
655 if (flowPath.flowEntryMatch().matchDstMac()) {
656 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
657 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700658 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
659 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
660 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700661 if (flowPath.flowEntryMatch().matchVlanId()) {
662 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
663 }
664 if (flowPath.flowEntryMatch().matchVlanPriority()) {
665 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
666 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700667 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
668 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
669 }
670 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
671 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
672 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700673 if (flowPath.flowEntryMatch().matchIpProto()) {
674 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700675 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700676 if (flowPath.flowEntryMatch().matchIpToS()) {
677 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
678 }
679 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
680 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
681 }
682 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
683 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700684 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700685 if (! flowPath.flowEntryActions().actions().isEmpty()) {
686 flowObj.setActions(flowPath.flowEntryActions().toString());
687 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800688
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700689 if (dataPathSummaryStr != null) {
690 flowObj.setDataPathSummary(dataPathSummaryStr);
691 } else {
692 flowObj.setDataPathSummary("");
693 }
694
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000695 if (found)
696 flowObj.setUserState("FE_USER_MODIFY");
697 else
698 flowObj.setUserState("FE_USER_ADD");
699
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800700 // Flow edges:
701 // HeadFE
702
703
704 //
705 // Flow Entries:
706 // flowPath.dataPath().flowEntries()
707 //
708 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700709 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700710 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800711 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700712 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800713 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700714 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800715
716 //
717 // TODO: We need a proper Flow ID allocation mechanism.
718 //
719 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700720
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800721 return true;
722 }
723
724 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700725 * Add a flow entry to the Network MAP.
726 *
727 * @param flowObj the corresponding Flow Path object for the Flow Entry.
728 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700729 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700730 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700731 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700732 // Flow edges
733 // HeadFE (TODO)
734
735 //
736 // Assign the FlowEntry ID.
737 //
738 if ((flowEntry.flowEntryId() == null) ||
739 (flowEntry.flowEntryId().value() == 0)) {
740 long id = getNextFlowEntryId();
741 flowEntry.setFlowEntryId(new FlowEntryId(id));
742 }
743
744 IFlowEntry flowEntryObj = null;
745 boolean found = false;
746 try {
747 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700748 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700749 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
750 flowEntry.flowEntryId().toString());
751 found = true;
752 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700753 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700754 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
755 flowEntry.flowEntryId().toString());
756 }
757 } catch (Exception e) {
758 log.error(":addFlow FlowEntryId:{} failed",
759 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700760 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700761 }
762 if (flowEntryObj == null) {
763 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
764 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700765 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700766 }
767
768 //
769 // Set the Flow Entry key:
770 // - flowEntry.flowEntryId()
771 //
772 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
773 flowEntryObj.setType("flow_entry");
774
775 //
776 // Set the Flow Entry Edges and attributes:
777 // - Switch edge
778 // - InPort edge
779 // - OutPort edge
780 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700781 // - flowEntry.dpid()
782 // - flowEntry.flowEntryUserState()
783 // - flowEntry.flowEntrySwitchState()
784 // - flowEntry.flowEntryErrorState()
785 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700786 // - flowEntry.matchSrcMac()
787 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700788 // - flowEntry.matchEthernetFrameType()
789 // - flowEntry.matchVlanId()
790 // - flowEntry.matchVlanPriority()
791 // - flowEntry.matchSrcIPv4Net()
792 // - flowEntry.matchDstIPv4Net()
793 // - flowEntry.matchIpProto()
794 // - flowEntry.matchIpToS()
795 // - flowEntry.matchSrcTcpUdpPort()
796 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700797 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700798 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700799 //
admin944ef4f2013-10-08 17:48:37 -0700800 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700801 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
802 flowEntryObj.setSwitch(sw);
803 if (flowEntry.flowEntryMatch().matchInPort()) {
804 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700805 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700806 flowEntry.flowEntryMatch().inPort().value());
807 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
808 flowEntryObj.setInPort(inport);
809 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700810 if (flowEntry.flowEntryMatch().matchSrcMac()) {
811 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
812 }
813 if (flowEntry.flowEntryMatch().matchDstMac()) {
814 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
815 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700816 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
817 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
818 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700819 if (flowEntry.flowEntryMatch().matchVlanId()) {
820 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
821 }
822 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
823 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
824 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700825 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
826 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
827 }
828 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
829 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
830 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700831 if (flowEntry.flowEntryMatch().matchIpProto()) {
832 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700833 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700834 if (flowEntry.flowEntryMatch().matchIpToS()) {
835 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
836 }
837 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
838 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
839 }
840 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
841 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700842 }
843
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700844 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700845 if (fa.actionOutput() != null) {
846 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700847 op.searchPort(flowEntry.dpid().toString(),
848 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700849 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700850 flowEntryObj.setOutPort(outport);
851 }
852 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700853 if (! flowEntry.flowEntryActions().isEmpty()) {
854 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
855 }
856
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700857 // TODO: Hacks with hard-coded state names!
858 if (found)
859 flowEntryObj.setUserState("FE_USER_MODIFY");
860 else
861 flowEntryObj.setUserState("FE_USER_ADD");
862 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
863 //
864 // TODO: Take care of the FlowEntryErrorState.
865 //
866
867 // Flow Entries edges:
868 // Flow
869 // NextFE (TODO)
870 if (! found) {
871 flowObj.addFlowEntry(flowEntryObj);
872 flowEntryObj.setFlow(flowObj);
873 }
874
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700875 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700876 }
877
878 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000879 * Delete all previously added flows.
880 *
881 * @return true on success, otherwise false.
882 */
883 @Override
884 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000885 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
886 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000887
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000888 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700889 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000890 for (IFlowPath flowPathObj : allFlowPaths) {
891 if (flowPathObj == null)
892 continue;
893 String flowIdStr = flowPathObj.getFlowId();
894 if (flowIdStr == null)
895 continue;
896 FlowId flowId = new FlowId(flowIdStr);
897 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000898 }
899
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000900 // Delete all flows one-by-one
901 for (FlowId flowId : concurrentAllFlowIds)
902 deleteFlow(flowId);
903
904 /*
905 * TODO: A faster mechanism to delete the Flow Paths by using
906 * a number of threads. Commented-out for now.
907 */
908 /*
909 //
910 // Create the threads to delete the Flow Paths
911 //
Yuta HIGUCHI6f0e4392013-10-09 17:43:34 -0700912 List<Thread> threads = new LinkedList<Thread>();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000913 for (int i = 0; i < 10; i++) {
914 Thread thread = new Thread(new Runnable() {
915 @Override
916 public void run() {
917 while (true) {
918 FlowId flowId = concurrentAllFlowIds.poll();
919 if (flowId == null)
920 return;
921 deleteFlow(flowId);
922 }
923 }}, "Delete All Flow Paths");
924 threads.add(thread);
925 }
926
927 // Start processing
928 for (Thread thread : threads) {
929 thread.start();
930 }
931
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000932 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000933 for (Thread thread : threads) {
934 try {
935 thread.join();
936 } catch (InterruptedException e) {
937 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
938 }
939 }
940 */
941
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000942 return true;
943 }
944
945 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800946 * Delete a previously added flow.
947 *
948 * @param flowId the Flow ID of the flow to delete.
949 * @return true on success, otherwise false.
950 */
951 @Override
952 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700953 /*
954 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700955 if (flowId.value() == measurementFlowId) {
956 modifiedMeasurementFlowTime = System.nanoTime();
957 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700958 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700959
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800960 IFlowPath flowObj = null;
961 //
962 // We just mark the entries for deletion,
963 // and let the switches remove each individual entry after
964 // it has been removed from the switches.
965 //
966 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700967 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800968 != null) {
969 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
970 flowId.toString());
971 } else {
972 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
973 flowId.toString());
974 }
975 } catch (Exception e) {
976 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700977 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800978 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
979 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700980 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700981 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800982 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700983 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800984
985 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000986 // Find and mark for deletion all Flow Entries,
987 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800988 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000989 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800990 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
991 boolean empty = true; // TODO: an ugly hack
992 for (IFlowEntry flowEntryObj : flowEntries) {
993 empty = false;
994 // flowObj.removeFlowEntry(flowEntryObj);
995 // conn.utils().removeFlowEntry(conn, flowEntryObj);
996 flowEntryObj.setUserState("FE_USER_DELETE");
997 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
998 }
999 // Remove from the database empty flows
1000 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001001 op.removeFlowPath(flowObj);
1002 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001003
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001004 return true;
1005 }
1006
1007 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001008 * Clear the state for all previously added flows.
1009 *
1010 * @return true on success, otherwise false.
1011 */
1012 @Override
1013 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001014 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001015
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001016 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001017 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001018 for (IFlowPath flowPathObj : allFlowPaths) {
1019 if (flowPathObj == null)
1020 continue;
1021 String flowIdStr = flowPathObj.getFlowId();
1022 if (flowIdStr == null)
1023 continue;
1024 FlowId flowId = new FlowId(flowIdStr);
1025 allFlowIds.add(flowId);
1026 }
1027
1028 // Clear all flows one-by-one
1029 for (FlowId flowId : allFlowIds) {
1030 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001031 }
1032
1033 return true;
1034 }
1035
1036 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001037 * Clear the state for a previously added flow.
1038 *
1039 * @param flowId the Flow ID of the flow to clear.
1040 * @return true on success, otherwise false.
1041 */
1042 @Override
1043 public boolean clearFlow(FlowId flowId) {
1044 IFlowPath flowObj = null;
1045 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001046 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001047 != null) {
1048 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1049 flowId.toString());
1050 } else {
1051 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1052 flowId.toString());
1053 }
1054 } catch (Exception e) {
1055 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001056 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001057 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1058 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001059 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001060 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001061 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001062 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001063
1064 //
1065 // Remove all Flow Entries
1066 //
1067 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1068 for (IFlowEntry flowEntryObj : flowEntries) {
1069 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001070 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001071 }
1072 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001073 op.removeFlowPath(flowObj);
1074 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001075
1076 return true;
1077 }
1078
1079 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001080 * Get a previously added flow.
1081 *
1082 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001083 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001084 */
1085 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001086 public FlowPath getFlow(FlowId flowId) {
1087 IFlowPath flowObj = null;
1088 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001089 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001090 != null) {
1091 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1092 flowId.toString());
1093 } else {
1094 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1095 flowId.toString());
1096 }
1097 } catch (Exception e) {
1098 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001099 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001100 log.error(":getFlow FlowId:{} failed", flowId.toString());
1101 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001102 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001103 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001104 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001105 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001106
1107 //
1108 // Extract the Flow state
1109 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001110 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001111 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001112
1113 return flowPath;
1114 }
1115
1116 /**
1117 * Get all previously added flows by a specific installer for a given
1118 * data path endpoints.
1119 *
1120 * @param installerId the Caller ID of the installer of the flow to get.
1121 * @param dataPathEndpoints the data path endpoints of the flow to get.
1122 * @return the Flow Paths if found, otherwise null.
1123 */
1124 @Override
1125 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1126 DataPathEndpoints dataPathEndpoints) {
1127 //
1128 // TODO: The implementation below is not optimal:
1129 // We fetch all flows, and then return only the subset that match
1130 // the query conditions.
1131 // We should use the appropriate Titan/Gremlin query to filter-out
1132 // the flows as appropriate.
1133 //
1134 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001135 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001136
1137 if (allFlows == null) {
1138 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001139 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001140 }
1141
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001142 for (FlowPath flow : allFlows) {
1143 //
1144 // TODO: String-based comparison is sub-optimal.
1145 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001146 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001147 //
1148 if (! flow.installerId().toString().equals(installerId.toString()))
1149 continue;
1150 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1151 continue;
1152 }
1153 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1154 continue;
1155 }
1156 flowPaths.add(flow);
1157 }
1158
1159 if (flowPaths.isEmpty()) {
1160 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001161 } else {
1162 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1163 }
1164
1165 return flowPaths;
1166 }
1167
1168 /**
1169 * Get all installed flows by all installers for given data path endpoints.
1170 *
1171 * @param dataPathEndpoints the data path endpoints of the flows to get.
1172 * @return the Flow Paths if found, otherwise null.
1173 */
1174 @Override
1175 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1176 //
1177 // TODO: The implementation below is not optimal:
1178 // We fetch all flows, and then return only the subset that match
1179 // the query conditions.
1180 // We should use the appropriate Titan/Gremlin query to filter-out
1181 // the flows as appropriate.
1182 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001183 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1184 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001185
1186 if (allFlows == null) {
1187 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001188 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001189 }
1190
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001191 for (FlowPath flow : allFlows) {
1192 //
1193 // TODO: String-based comparison is sub-optimal.
1194 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001195 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001196 //
1197 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1198 continue;
1199 }
1200 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1201 continue;
1202 }
1203 flowPaths.add(flow);
1204 }
1205
1206 if (flowPaths.isEmpty()) {
1207 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001208 } else {
1209 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1210 }
1211
1212 return flowPaths;
1213 }
1214
1215 /**
admin944ef4f2013-10-08 17:48:37 -07001216 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001217 *
admin944ef4f2013-10-08 17:48:37 -07001218 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001219 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001220 * @return the Flow Paths if found, otherwise null.
1221 */
1222 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001223 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001224
admin944ef4f2013-10-08 17:48:37 -07001225 //
1226 // TODO: The implementation below is not optimal:
1227 // We fetch all flows, and then return only the subset that match
1228 // the query conditions.
1229 // We should use the appropriate Titan/Gremlin query to filter-out
1230 // the flows as appropriate.
1231 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001232 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001233
Jonathan Hart01f2d272013-04-04 20:03:46 -07001234 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1235
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001236 Collections.sort(flowPathsWithoutFlowEntries,
1237 new Comparator<IFlowPath>(){
1238 @Override
1239 public int compare(IFlowPath first, IFlowPath second) {
1240 // TODO Auto-generated method stub
1241 long result = new FlowId(first.getFlowId()).value()
1242 - new FlowId(second.getFlowId()).value();
1243 if (result > 0) return 1;
1244 else if (result < 0) return -1;
1245 else return 0;
1246 }
1247 }
1248 );
1249
Jonathan Hart01f2d272013-04-04 20:03:46 -07001250 return flowPathsWithoutFlowEntries;
1251
1252 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001253 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001254
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001255 if (allFlows == null) {
1256 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001257 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001258 }
1259
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001260 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001261
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001262 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001263 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001264
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001265 // start from desired flowId
1266 if (flow.flowId().value() < flowId.value()) {
1267 continue;
1268 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001269
1270 // Summarize by making null flow entry fields that are not relevant to report
1271 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1272 flowEntry.setFlowEntryActions(null);
1273 flowEntry.setFlowEntryMatch(null);
1274 }
1275
1276 flowPaths.add(flow);
1277 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1278 break;
1279 }
1280 }
1281
1282 if (flowPaths.isEmpty()) {
1283 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001284 } else {
1285 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1286 }
1287
1288 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001289 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001290 }
1291
1292 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001293 * Get all installed flows by all installers.
1294 *
1295 * @return the Flow Paths if found, otherwise null.
1296 */
1297 @Override
1298 public ArrayList<FlowPath> getAllFlows() {
1299 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001300 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001301
1302 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001303 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001304 log.debug("Get all FlowPaths: found FlowPaths");
1305 } else {
1306 log.debug("Get all FlowPaths: no FlowPaths found");
1307 }
1308 } catch (Exception e) {
1309 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001310 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001311 log.error(":getAllFlowPaths failed");
1312 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001313 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001314 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001315 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001316 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001317
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001318 for (IFlowPath flowObj : flowPathsObj) {
1319 //
1320 // Extract the Flow state
1321 //
1322 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001323 if (flowPath != null)
1324 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001325 }
1326
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001327 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001328
1329 return flowPaths;
1330 }
admin944ef4f2013-10-08 17:48:37 -07001331
1332 /**
1333 * Get all Flows information, without the associated Flow Entries.
1334 *
1335 * @return all Flows information, without the associated Flow Entries.
1336 */
1337 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001338 Iterable<IFlowPath> flowPathsObj = null;
1339 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001340
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001341 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001342
Jonathan Hart01f2d272013-04-04 20:03:46 -07001343 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001344 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001345 log.debug("Get all FlowPaths: found FlowPaths");
1346 } else {
1347 log.debug("Get all FlowPaths: no FlowPaths found");
1348 }
1349 } catch (Exception e) {
1350 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001351 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001352 log.error(":getAllFlowPaths failed");
1353 }
1354 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1355 return new ArrayList<IFlowPath>(); // No Flows found
1356 }
1357
1358 for (IFlowPath flowObj : flowPathsObj){
1359 flowPathsObjArray.add(flowObj);
1360 }
1361 /*
Yuta HIGUCHI1e3eba82013-10-09 17:34:54 -07001362 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001363 for (IFlowPath flowObj : flowPathsObj) {
1364 //
1365 // Extract the Flow state
1366 //
1367 FlowPath flowPath = extractFlowPath(flowObj);
1368 if (flowPath != null)
1369 flowPaths.add(flowPath);
1370 }
1371 */
1372
1373 //conn.endTx(Transaction.COMMIT);
1374
1375 return flowPathsObjArray;
1376 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001377
1378 /**
1379 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1380 *
1381 * @param flowObj the object to extract the Flow Path State from.
1382 * @return the extracted Flow Path State.
1383 */
1384 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001385 //
1386 // Extract the Flow state
1387 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001388 String flowIdStr = flowObj.getFlowId();
1389 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001390 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001391 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001392 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001393 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001394 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001395
1396 if ((flowIdStr == null) ||
1397 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001398 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001399 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001400 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001401 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001402 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001403 // TODO: A work-around, becauuse of some bogus database objects
1404 return null;
1405 }
1406
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001407 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001408 flowPath.setFlowId(new FlowId(flowIdStr));
1409 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001410 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001411 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001412 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001413 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001414 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001415 //
1416 // Extract the match conditions common for all Flow Entries
1417 //
1418 {
1419 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001420 String matchSrcMac = flowObj.getMatchSrcMac();
1421 if (matchSrcMac != null)
1422 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1423 String matchDstMac = flowObj.getMatchDstMac();
1424 if (matchDstMac != null)
1425 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001426 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1427 if (matchEthernetFrameType != null)
1428 match.enableEthernetFrameType(matchEthernetFrameType);
1429 Short matchVlanId = flowObj.getMatchVlanId();
1430 if (matchVlanId != null)
1431 match.enableVlanId(matchVlanId);
1432 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1433 if (matchVlanPriority != null)
1434 match.enableVlanPriority(matchVlanPriority);
1435 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1436 if (matchSrcIPv4Net != null)
1437 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1438 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1439 if (matchDstIPv4Net != null)
1440 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1441 Byte matchIpProto = flowObj.getMatchIpProto();
1442 if (matchIpProto != null)
1443 match.enableIpProto(matchIpProto);
1444 Byte matchIpToS = flowObj.getMatchIpToS();
1445 if (matchIpToS != null)
1446 match.enableIpToS(matchIpToS);
1447 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1448 if (matchSrcTcpUdpPort != null)
1449 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1450 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1451 if (matchDstTcpUdpPort != null)
1452 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1453
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001454 flowPath.setFlowEntryMatch(match);
1455 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001456 //
1457 // Extract the actions for the first Flow Entry
1458 //
1459 {
1460 String actionsStr = flowObj.getActions();
1461 if (actionsStr != null) {
1462 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1463 flowPath.setFlowEntryActions(flowEntryActions);
1464 }
1465 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001466
1467 //
1468 // Extract all Flow Entries
1469 //
1470 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1471 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001472 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1473 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001474 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001475 flowPath.dataPath().flowEntries().add(flowEntry);
1476 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001477
1478 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001479 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001480
1481 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001482 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1483 *
1484 * @param flowEntryObj the object to extract the Flow Entry State from.
1485 * @return the extracted Flow Entry State.
1486 */
1487 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1488 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1489 String switchDpidStr = flowEntryObj.getSwitchDpid();
1490 String userState = flowEntryObj.getUserState();
1491 String switchState = flowEntryObj.getSwitchState();
1492
1493 if ((flowEntryIdStr == null) ||
1494 (switchDpidStr == null) ||
1495 (userState == null) ||
1496 (switchState == null)) {
1497 // TODO: A work-around, becauuse of some bogus database objects
1498 return null;
1499 }
1500
1501 FlowEntry flowEntry = new FlowEntry();
1502 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1503 flowEntry.setDpid(new Dpid(switchDpidStr));
1504
1505 //
1506 // Extract the match conditions
1507 //
1508 FlowEntryMatch match = new FlowEntryMatch();
1509 Short matchInPort = flowEntryObj.getMatchInPort();
1510 if (matchInPort != null)
1511 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001512 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1513 if (matchSrcMac != null)
1514 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1515 String matchDstMac = flowEntryObj.getMatchDstMac();
1516 if (matchDstMac != null)
1517 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001518 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1519 if (matchEthernetFrameType != null)
1520 match.enableEthernetFrameType(matchEthernetFrameType);
1521 Short matchVlanId = flowEntryObj.getMatchVlanId();
1522 if (matchVlanId != null)
1523 match.enableVlanId(matchVlanId);
1524 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1525 if (matchVlanPriority != null)
1526 match.enableVlanPriority(matchVlanPriority);
1527 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1528 if (matchSrcIPv4Net != null)
1529 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1530 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1531 if (matchDstIPv4Net != null)
1532 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1533 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1534 if (matchIpProto != null)
1535 match.enableIpProto(matchIpProto);
1536 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1537 if (matchIpToS != null)
1538 match.enableIpToS(matchIpToS);
1539 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1540 if (matchSrcTcpUdpPort != null)
1541 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1542 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1543 if (matchDstTcpUdpPort != null)
1544 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001545 flowEntry.setFlowEntryMatch(match);
1546
1547 //
1548 // Extract the actions
1549 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001550 FlowEntryActions actions = new FlowEntryActions();
1551 String actionsStr = flowEntryObj.getActions();
1552 if (actionsStr != null)
1553 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001554 flowEntry.setFlowEntryActions(actions);
1555 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1556 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1557 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001558 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001559 //
1560 return flowEntry;
1561 }
1562
1563 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001564 * Add and maintain a shortest-path flow.
1565 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001566 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001567 *
1568 * @param flowPath the Flow Path with the endpoints and the match
1569 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001570 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001571 */
1572 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001573 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001574 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001575 // Don't do the shortest path computation here.
1576 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001577 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001578
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001579 // We need the DataPath to populate the Network MAP
1580 DataPath dataPath = new DataPath();
1581 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1582 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001583
1584 //
1585 // Prepare the computed Flow Path
1586 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001587 FlowPath computedFlowPath = new FlowPath();
1588 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1589 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001590 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001591 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001592 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001593 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001594
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001595 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001596 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001597 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001598 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001599
1600 // TODO: Mark the flow for maintenance purpose
1601
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001602 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001603 }
1604
1605 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001606 * Reconcile a flow.
1607 *
1608 * @param flowObj the flow that needs to be reconciliated.
1609 * @param newDataPath the new data path to use.
1610 * @return true on success, otherwise false.
1611 */
1612 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001613
1614 //
1615 // Set the incoming port matching and the outgoing port output
1616 // actions for each flow entry.
1617 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001618 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001619 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1620 // Set the incoming port matching
1621 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1622 flowEntry.setFlowEntryMatch(flowEntryMatch);
1623 flowEntryMatch.enableInPort(flowEntry.inPort());
1624
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001625 //
1626 // Set the actions
1627 //
1628 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1629 //
1630 // If the first Flow Entry, copy the Flow Path actions to it
1631 //
1632 if (idx == 0) {
1633 String actionsStr = flowObj.getActions();
1634 if (actionsStr != null) {
1635 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1636 for (FlowEntryAction action : flowActions.actions())
1637 flowEntryActions.addAction(action);
1638 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001639 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001640 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001641 //
1642 // Add the outgoing port output action
1643 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001644 FlowEntryAction flowEntryAction = new FlowEntryAction();
1645 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001646 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001647 }
1648
1649 //
1650 // Remove the old Flow Entries, and add the new Flow Entries
1651 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001652 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001653 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001654 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001655 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001656 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001657 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001658 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001659 }
1660
1661 //
1662 // Set the Data Path Summary
1663 //
1664 String dataPathSummaryStr = newDataPath.dataPathSummary();
1665 flowObj.setDataPathSummary(dataPathSummaryStr);
1666
1667 return true;
1668 }
1669
1670 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001671 * Reconcile all flows in a set.
1672 *
1673 * @param flowObjSet the set of flows that need to be reconciliated.
1674 */
1675 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1676 if (! flowObjSet.iterator().hasNext())
1677 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001678 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001679 }
1680
1681 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001682 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001683 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001684 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001685 * @param flowObj the flow path object for the flow entry to install.
1686 * @param flowEntryObj the flow entry object to install.
1687 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001688 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001689 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1690 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001691 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1692 if (flowEntryIdStr == null)
1693 return false;
1694 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001695 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001696 if (userState == null)
1697 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001698
1699 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001700 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001701 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001702 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1703 .getMessage(OFType.FLOW_MOD);
1704 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001705
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001706 short flowModCommand = OFFlowMod.OFPFC_ADD;
1707 if (userState.equals("FE_USER_ADD")) {
1708 flowModCommand = OFFlowMod.OFPFC_ADD;
1709 } else if (userState.equals("FE_USER_MODIFY")) {
1710 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1711 } else if (userState.equals("FE_USER_DELETE")) {
1712 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1713 } else {
1714 // Unknown user state. Ignore the entry
1715 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1716 flowEntryId.toString(), userState);
1717 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001718 }
1719
1720 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001721 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001722 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001723 // NOTE: The Flow matching conditions common for all Flow Entries are
1724 // used ONLY if a Flow Entry does NOT have the corresponding matching
1725 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001726 //
1727 OFMatch match = new OFMatch();
1728 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001729
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001730 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001731 Short matchInPort = flowEntryObj.getMatchInPort();
1732 if (matchInPort != null) {
1733 match.setInputPort(matchInPort);
1734 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1735 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001736
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001737 // Match the Source MAC address
1738 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1739 if (matchSrcMac == null)
1740 matchSrcMac = flowObj.getMatchSrcMac();
1741 if (matchSrcMac != null) {
1742 match.setDataLayerSource(matchSrcMac);
1743 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1744 }
1745
1746 // Match the Destination MAC address
1747 String matchDstMac = flowEntryObj.getMatchDstMac();
1748 if (matchDstMac == null)
1749 matchDstMac = flowObj.getMatchDstMac();
1750 if (matchDstMac != null) {
1751 match.setDataLayerDestination(matchDstMac);
1752 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1753 }
1754
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001755 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001756 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1757 if (matchEthernetFrameType == null)
1758 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1759 if (matchEthernetFrameType != null) {
1760 match.setDataLayerType(matchEthernetFrameType);
1761 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1762 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001763
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001764 // Match the VLAN ID
1765 Short matchVlanId = flowEntryObj.getMatchVlanId();
1766 if (matchVlanId == null)
1767 matchVlanId = flowObj.getMatchVlanId();
1768 if (matchVlanId != null) {
1769 match.setDataLayerVirtualLan(matchVlanId);
1770 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1771 }
1772
1773 // Match the VLAN priority
1774 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1775 if (matchVlanPriority == null)
1776 matchVlanPriority = flowObj.getMatchVlanPriority();
1777 if (matchVlanPriority != null) {
1778 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1779 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1780 }
1781
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001782 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001783 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1784 if (matchSrcIPv4Net == null)
1785 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1786 if (matchSrcIPv4Net != null) {
1787 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1788 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001789
1790 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001791 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1792 if (matchDstIPv4Net == null)
1793 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1794 if (matchDstIPv4Net != null) {
1795 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1796 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001797
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001798 // Match the IP protocol
1799 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1800 if (matchIpProto == null)
1801 matchIpProto = flowObj.getMatchIpProto();
1802 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001803 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001804 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001805 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001806
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001807 // Match the IP ToS (DSCP field, 6 bits)
1808 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1809 if (matchIpToS == null)
1810 matchIpToS = flowObj.getMatchIpToS();
1811 if (matchIpToS != null) {
1812 match.setNetworkTypeOfService(matchIpToS);
1813 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1814 }
1815
1816 // Match the Source TCP/UDP port
1817 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1818 if (matchSrcTcpUdpPort == null)
1819 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1820 if (matchSrcTcpUdpPort != null) {
1821 match.setTransportSource(matchSrcTcpUdpPort);
1822 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1823 }
1824
1825 // Match the Destination TCP/UDP port
1826 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1827 if (matchDstTcpUdpPort == null)
1828 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1829 if (matchDstTcpUdpPort != null) {
1830 match.setTransportDestination(matchDstTcpUdpPort);
1831 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001832 }
1833
1834 //
1835 // Fetch the actions
1836 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001837 Short actionOutputPort = null;
1838 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1839 int actionsLen = 0;
1840 FlowEntryActions flowEntryActions = null;
1841 String actionsStr = flowEntryObj.getActions();
1842 if (actionsStr != null)
1843 flowEntryActions = new FlowEntryActions(actionsStr);
1844 for (FlowEntryAction action : flowEntryActions.actions()) {
1845 ActionOutput actionOutput = action.actionOutput();
1846 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1847 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1848 ActionStripVlan actionStripVlan = action.actionStripVlan();
1849 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1850 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1851 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1852 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1853 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1854 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1855 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1856 ActionEnqueue actionEnqueue = action.actionEnqueue();
1857
1858 if (actionOutput != null) {
1859 actionOutputPort = actionOutput.port().value();
1860 // XXX: The max length is hard-coded for now
1861 OFActionOutput ofa =
1862 new OFActionOutput(actionOutput.port().value(),
1863 (short)0xffff);
1864 openFlowActions.add(ofa);
1865 actionsLen += ofa.getLength();
1866 }
1867
1868 if (actionSetVlanId != null) {
1869 OFActionVirtualLanIdentifier ofa =
1870 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1871 openFlowActions.add(ofa);
1872 actionsLen += ofa.getLength();
1873 }
1874
1875 if (actionSetVlanPriority != null) {
1876 OFActionVirtualLanPriorityCodePoint ofa =
1877 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1878 openFlowActions.add(ofa);
1879 actionsLen += ofa.getLength();
1880 }
1881
1882 if (actionStripVlan != null) {
1883 if (actionStripVlan.stripVlan() == true) {
1884 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1885 openFlowActions.add(ofa);
1886 actionsLen += ofa.getLength();
1887 }
1888 }
1889
1890 if (actionSetEthernetSrcAddr != null) {
1891 OFActionDataLayerSource ofa =
1892 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1893 openFlowActions.add(ofa);
1894 actionsLen += ofa.getLength();
1895 }
1896
1897 if (actionSetEthernetDstAddr != null) {
1898 OFActionDataLayerDestination ofa =
1899 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1900 openFlowActions.add(ofa);
1901 actionsLen += ofa.getLength();
1902 }
1903
1904 if (actionSetIPv4SrcAddr != null) {
1905 OFActionNetworkLayerSource ofa =
1906 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1907 openFlowActions.add(ofa);
1908 actionsLen += ofa.getLength();
1909 }
1910
1911 if (actionSetIPv4DstAddr != null) {
1912 OFActionNetworkLayerDestination ofa =
1913 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1914 openFlowActions.add(ofa);
1915 actionsLen += ofa.getLength();
1916 }
1917
1918 if (actionSetIpToS != null) {
1919 OFActionNetworkTypeOfService ofa =
1920 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1921 openFlowActions.add(ofa);
1922 actionsLen += ofa.getLength();
1923 }
1924
1925 if (actionSetTcpUdpSrcPort != null) {
1926 OFActionTransportLayerSource ofa =
1927 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1928 openFlowActions.add(ofa);
1929 actionsLen += ofa.getLength();
1930 }
1931
1932 if (actionSetTcpUdpDstPort != null) {
1933 OFActionTransportLayerDestination ofa =
1934 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1935 openFlowActions.add(ofa);
1936 actionsLen += ofa.getLength();
1937 }
1938
1939 if (actionEnqueue != null) {
1940 OFActionEnqueue ofa =
1941 new OFActionEnqueue(actionEnqueue.port().value(),
1942 actionEnqueue.queueId());
1943 openFlowActions.add(ofa);
1944 actionsLen += ofa.getLength();
1945 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001946 }
1947
1948 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1949 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1950 .setPriority(PRIORITY_DEFAULT)
1951 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1952 .setCookie(cookie)
1953 .setCommand(flowModCommand)
1954 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001955 .setActions(openFlowActions)
1956 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001957 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1958 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1959 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1960 if (actionOutputPort != null)
1961 fm.setOutPort(actionOutputPort);
1962 }
1963
1964 //
1965 // TODO: Set the following flag
1966 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1967 // See method ForwardingBase::pushRoute()
1968 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001969
1970 //
1971 // Write the message to the switch
1972 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001973 log.debug("MEASUREMENT: Installing flow entry " + userState +
1974 " into switch DPID: " +
1975 mySwitch.getStringId() +
1976 " flowEntryId: " + flowEntryId.toString() +
1977 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1978 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1979 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001980 try {
1981 messageDamper.write(mySwitch, fm, null);
1982 mySwitch.flush();
1983 //
1984 // TODO: We should use the OpenFlow Barrier mechanism
1985 // to check for errors, and update the SwitchState
1986 // for a flow entry after the Barrier message is
1987 // is received.
1988 //
1989 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1990 } catch (IOException e) {
1991 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001992 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001993 }
1994
1995 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001996 }
1997
1998 /**
1999 * Install a Flow Entry on a switch.
2000 *
2001 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002002 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002003 * @param flowEntry the flow entry to install.
2004 * @return true on success, otherwise false.
2005 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002006 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2007 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002008 //
2009 // Create the OpenFlow Flow Modification Entry to push
2010 //
2011 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
2012 .getMessage(OFType.FLOW_MOD);
2013 long cookie = flowEntry.flowEntryId().value();
2014
2015 short flowModCommand = OFFlowMod.OFPFC_ADD;
2016 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
2017 flowModCommand = OFFlowMod.OFPFC_ADD;
2018 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
2019 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
2020 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
2021 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
2022 } else {
2023 // Unknown user state. Ignore the entry
2024 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
2025 flowEntry.flowEntryId().toString(),
2026 flowEntry.flowEntryUserState());
2027 return false;
2028 }
2029
2030 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002031 // Fetch the match conditions.
2032 //
2033 // NOTE: The Flow matching conditions common for all Flow Entries are
2034 // used ONLY if a Flow Entry does NOT have the corresponding matching
2035 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002036 //
2037 OFMatch match = new OFMatch();
2038 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002039 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
2040 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
2041
2042 // Match the Incoming Port
2043 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002044 if (matchInPort != null) {
2045 match.setInputPort(matchInPort.value());
2046 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
2047 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002048
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002049 // Match the Source MAC address
2050 MACAddress matchSrcMac = flowEntryMatch.srcMac();
2051 if ((matchSrcMac == null) && (flowPathMatch != null)) {
2052 matchSrcMac = flowPathMatch.srcMac();
2053 }
2054 if (matchSrcMac != null) {
2055 match.setDataLayerSource(matchSrcMac.toString());
2056 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2057 }
2058
2059 // Match the Destination MAC address
2060 MACAddress matchDstMac = flowEntryMatch.dstMac();
2061 if ((matchDstMac == null) && (flowPathMatch != null)) {
2062 matchDstMac = flowPathMatch.dstMac();
2063 }
2064 if (matchDstMac != null) {
2065 match.setDataLayerDestination(matchDstMac.toString());
2066 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2067 }
2068
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002069 // Match the Ethernet Frame Type
2070 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2071 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2072 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2073 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002074 if (matchEthernetFrameType != null) {
2075 match.setDataLayerType(matchEthernetFrameType);
2076 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2077 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002078
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002079 // Match the VLAN ID
2080 Short matchVlanId = flowEntryMatch.vlanId();
2081 if ((matchVlanId == null) && (flowPathMatch != null)) {
2082 matchVlanId = flowPathMatch.vlanId();
2083 }
2084 if (matchVlanId != null) {
2085 match.setDataLayerVirtualLan(matchVlanId);
2086 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2087 }
2088
2089 // Match the VLAN priority
2090 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2091 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2092 matchVlanPriority = flowPathMatch.vlanPriority();
2093 }
2094 if (matchVlanPriority != null) {
2095 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2096 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2097 }
2098
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002099 // Match the Source IPv4 Network prefix
2100 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2101 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2102 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2103 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002104 if (matchSrcIPv4Net != null) {
2105 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2106 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002107
2108 // Natch the Destination IPv4 Network prefix
2109 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2110 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2111 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2112 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002113 if (matchDstIPv4Net != null) {
2114 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2115 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002116
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002117 // Match the IP protocol
2118 Byte matchIpProto = flowEntryMatch.ipProto();
2119 if ((matchIpProto == null) && (flowPathMatch != null)) {
2120 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002121 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002122 if (matchIpProto != null) {
2123 match.setNetworkProtocol(matchIpProto);
2124 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002125 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002126
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002127 // Match the IP ToS (DSCP field, 6 bits)
2128 Byte matchIpToS = flowEntryMatch.ipToS();
2129 if ((matchIpToS == null) && (flowPathMatch != null)) {
2130 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002131 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002132 if (matchIpToS != null) {
2133 match.setNetworkTypeOfService(matchIpToS);
2134 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2135 }
2136
2137 // Match the Source TCP/UDP port
2138 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2139 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2140 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2141 }
2142 if (matchSrcTcpUdpPort != null) {
2143 match.setTransportSource(matchSrcTcpUdpPort);
2144 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2145 }
2146
2147 // Match the Destination TCP/UDP port
2148 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2149 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2150 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2151 }
2152 if (matchDstTcpUdpPort != null) {
2153 match.setTransportDestination(matchDstTcpUdpPort);
2154 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002155 }
2156
2157 //
2158 // Fetch the actions
2159 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002160 Short actionOutputPort = null;
2161 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2162 int actionsLen = 0;
2163 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002164 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002165 for (FlowEntryAction action : flowEntryActions.actions()) {
2166 ActionOutput actionOutput = action.actionOutput();
2167 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2168 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2169 ActionStripVlan actionStripVlan = action.actionStripVlan();
2170 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2171 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2172 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2173 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2174 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2175 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2176 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2177 ActionEnqueue actionEnqueue = action.actionEnqueue();
2178
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002179 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002180 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002181 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002182 OFActionOutput ofa =
2183 new OFActionOutput(actionOutput.port().value(),
2184 (short)0xffff);
2185 openFlowActions.add(ofa);
2186 actionsLen += ofa.getLength();
2187 }
2188
2189 if (actionSetVlanId != null) {
2190 OFActionVirtualLanIdentifier ofa =
2191 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2192 openFlowActions.add(ofa);
2193 actionsLen += ofa.getLength();
2194 }
2195
2196 if (actionSetVlanPriority != null) {
2197 OFActionVirtualLanPriorityCodePoint ofa =
2198 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2199 openFlowActions.add(ofa);
2200 actionsLen += ofa.getLength();
2201 }
2202
2203 if (actionStripVlan != null) {
2204 if (actionStripVlan.stripVlan() == true) {
2205 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2206 openFlowActions.add(ofa);
2207 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002208 }
2209 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002210
2211 if (actionSetEthernetSrcAddr != null) {
2212 OFActionDataLayerSource ofa =
2213 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2214 openFlowActions.add(ofa);
2215 actionsLen += ofa.getLength();
2216 }
2217
2218 if (actionSetEthernetDstAddr != null) {
2219 OFActionDataLayerDestination ofa =
2220 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2221 openFlowActions.add(ofa);
2222 actionsLen += ofa.getLength();
2223 }
2224
2225 if (actionSetIPv4SrcAddr != null) {
2226 OFActionNetworkLayerSource ofa =
2227 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2228 openFlowActions.add(ofa);
2229 actionsLen += ofa.getLength();
2230 }
2231
2232 if (actionSetIPv4DstAddr != null) {
2233 OFActionNetworkLayerDestination ofa =
2234 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2235 openFlowActions.add(ofa);
2236 actionsLen += ofa.getLength();
2237 }
2238
2239 if (actionSetIpToS != null) {
2240 OFActionNetworkTypeOfService ofa =
2241 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2242 openFlowActions.add(ofa);
2243 actionsLen += ofa.getLength();
2244 }
2245
2246 if (actionSetTcpUdpSrcPort != null) {
2247 OFActionTransportLayerSource ofa =
2248 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2249 openFlowActions.add(ofa);
2250 actionsLen += ofa.getLength();
2251 }
2252
2253 if (actionSetTcpUdpDstPort != null) {
2254 OFActionTransportLayerDestination ofa =
2255 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2256 openFlowActions.add(ofa);
2257 actionsLen += ofa.getLength();
2258 }
2259
2260 if (actionEnqueue != null) {
2261 OFActionEnqueue ofa =
2262 new OFActionEnqueue(actionEnqueue.port().value(),
2263 actionEnqueue.queueId());
2264 openFlowActions.add(ofa);
2265 actionsLen += ofa.getLength();
2266 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002267 }
2268
2269 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2270 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2271 .setPriority(PRIORITY_DEFAULT)
2272 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2273 .setCookie(cookie)
2274 .setCommand(flowModCommand)
2275 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002276 .setActions(openFlowActions)
2277 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2278 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2279 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2280 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2281 if (actionOutputPort != null)
2282 fm.setOutPort(actionOutputPort);
2283 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002284
2285 //
2286 // TODO: Set the following flag
2287 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2288 // See method ForwardingBase::pushRoute()
2289 //
2290
2291 //
2292 // Write the message to the switch
2293 //
2294 try {
2295 messageDamper.write(mySwitch, fm, null);
2296 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002297 //
2298 // TODO: We should use the OpenFlow Barrier mechanism
2299 // to check for errors, and update the SwitchState
2300 // for a flow entry after the Barrier message is
2301 // is received.
2302 //
2303 // TODO: The FlowEntry Object in Titan should be set
2304 // to FE_SWITCH_UPDATED.
2305 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002306 } catch (IOException e) {
2307 log.error("Failure writing flow mod from network map", e);
2308 return false;
2309 }
2310 return true;
2311 }
2312
2313 /**
2314 * Remove a Flow Entry from a switch.
2315 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002316 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002317 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002318 * @param flowEntry the flow entry to remove.
2319 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002320 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002321 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2322 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002323 //
2324 // The installFlowEntry() method implements both installation
2325 // and removal of flow entries.
2326 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002327 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002328 }
2329
2330 /**
2331 * Install a Flow Entry on a remote controller.
2332 *
2333 * TODO: We need it now: Jono
2334 * - For now it will make a REST call to the remote controller.
2335 * - Internally, it needs to know the name of the remote controller.
2336 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002337 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002338 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002339 * @return true on success, otherwise false.
2340 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002341 public boolean installRemoteFlowEntry(FlowPath flowPath,
2342 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002343 // TODO: We need it now: Jono
2344 // - For now it will make a REST call to the remote controller.
2345 // - Internally, it needs to know the name of the remote controller.
2346 return true;
2347 }
2348
2349 /**
2350 * Remove a flow entry on a remote controller.
2351 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002352 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002353 * @param flowEntry the flow entry to remove.
2354 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002355 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002356 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2357 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002358 //
2359 // The installRemoteFlowEntry() method implements both installation
2360 // and removal of flow entries.
2361 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002362 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002363 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002364}