blob: 82aa25c6e614d00660632086911b790246930d1f [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 Radoslavov9e5344c2013-02-18 09:58:30 -0800102 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800103 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
104
105 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700106 private ScheduledExecutorService mapReaderScheduler;
107 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700108
admin944ef4f2013-10-08 17:48:37 -0700109 /**
110 * Periodic task for reading the Flow Entries and pushing changes
111 * into the switches.
112 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700113 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800114 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700115 try {
116 runImpl();
117 } catch (Exception e) {
118 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700119 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700120 return;
121 }
122 }
123
124 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700125 long startTime = System.nanoTime();
126 int counterAllFlowEntries = 0;
127 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700128
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800129 if (floodlightProvider == null) {
130 log.debug("FloodlightProvider service not found!");
131 return;
132 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 Map<Long, IOFSwitch> mySwitches =
134 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700135 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700136 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700137 return;
138 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700139 LinkedList<IFlowEntry> addFlowEntries =
140 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000141 LinkedList<IFlowEntry> deleteFlowEntries =
142 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700143
144 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700145 // Fetch all Flow Entries which need to be updated and select
146 // only my Flow Entries that need to be updated into the
147 // switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700148 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000149 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700150 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700151 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700152 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000153
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000154 String dpidStr = flowEntryObj.getSwitchDpid();
155 if (dpidStr == null)
156 continue;
157 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800158 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000159 if (mySwitch == null)
160 continue; // Ignore the entry: not my switch
161
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700162 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700163 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700164 if (flowObj == null)
165 continue; // Should NOT happen
166 if (flowObj.getFlowId() == null)
167 continue; // Invalid entry
168
169 //
170 // NOTE: For now we process the DELETE before the ADD
171 // to cover the more common scenario.
172 // TODO: This is error prone and needs to be fixed!
173 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000174 String userState = flowEntryObj.getUserState();
175 if (userState == null)
176 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700177 if (userState.equals("FE_USER_DELETE")) {
178 // An entry that needs to be deleted.
179 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700180 installFlowEntry(mySwitch, flowObj, flowEntryObj);
181 } else {
182 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700183 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700184 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700185 }
186
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700187 //
188 // Process the Flow Entries that need to be added
189 //
190 for (IFlowEntry flowEntryObj : addFlowEntries) {
191 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700192 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700193 if (flowObj == null)
194 continue; // Should NOT happen
195 if (flowObj.getFlowId() == null)
196 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700197
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200 if (mySwitch == null)
201 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700202 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800203 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204
205 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000206 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700207 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000208 //
209 // TODO: We should use the OpenFlow Barrier mechanism
210 // to check for errors, and delete the Flow Entries after the
211 // Barrier message is received.
212 //
213 while (! deleteFlowEntries.isEmpty()) {
214 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
215 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700216 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000217 if (flowObj == null) {
218 log.debug("Did not find FlowPath to be deleted");
219 continue;
220 }
221 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700222 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000223 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700224
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700225 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700226
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700227 long estimatedTime = System.nanoTime() - startTime;
228 double rate = 0.0;
229 if (estimatedTime > 0)
230 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
231 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
232 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
233 counterMyNotUpdatedFlowEntries + " in " +
234 (double)estimatedTime / 1000000000 + " sec: " +
235 rate + " paths/s";
236 log.debug(logMsg);
237 }
238 };
239
admin944ef4f2013-10-08 17:48:37 -0700240 /**
241 * Periodic task for reading the Flow Paths and recomputing the
242 * shortest paths.
243 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700244 final Runnable shortestPathReconcile = new Runnable() {
245 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700246 try {
247 runImpl();
248 } catch (Exception e) {
249 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700250 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700251 return;
252 }
253 }
254
255 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700256 long startTime = System.nanoTime();
257 int counterAllFlowPaths = 0;
258 int counterMyFlowPaths = 0;
259
260 if (floodlightProvider == null) {
261 log.debug("FloodlightProvider service not found!");
262 return;
263 }
264 Map<Long, IOFSwitch> mySwitches =
265 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700266 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700267 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700268 return;
269 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700270 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
271
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700272 //
273 // Fetch and recompute the Shortest Path for those
274 // Flow Paths this controller is responsible for.
275 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700276 Topology topology = topologyNetService.newDatabaseTopology();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700277 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700278 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700279 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700280 if (flowPathObj == null)
281 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700282
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700283 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000284 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700285 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700286 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700287 //
288 // Use the source DPID as a heuristic to decide
289 // which controller is responsible for maintaining the
290 // shortest path.
291 // NOTE: This heuristic is error-prone: if the switch
292 // goes away and no controller is responsible for that
293 // switch, then the original Flow Path is not cleaned-up
294 //
295 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
296 if (mySwitch == null)
297 continue; // Ignore: not my responsibility
298
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700299 // Test the Data Path Summary string
300 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
301 if (dataPathSummaryStr == null)
302 continue; // Could be invalid entry?
303 if (dataPathSummaryStr.isEmpty())
304 continue; // No need to maintain this flow
305
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000306 //
307 // Test whether we need to complete the Flow cleanup,
308 // if the Flow has been deleted by the user.
309 //
310 String flowUserState = flowPathObj.getUserState();
311 if ((flowUserState != null)
312 && flowUserState.equals("FE_USER_DELETE")) {
313 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700314 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000315 if (empty)
316 deleteFlows.add(flowPathObj);
317 }
318
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000319 // Fetch the fields needed to recompute the shortest path
320 Short srcPortShort = flowPathObj.getSrcPort();
321 String dstDpidStr = flowPathObj.getDstSwitch();
322 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700323 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000324 if ((srcPortShort == null) ||
325 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700326 (dstPortShort == null) ||
327 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000328 continue;
329 }
330
331 Port srcPort = new Port(srcPortShort);
332 Dpid dstDpid = new Dpid(dstDpidStr);
333 Port dstPort = new Port(dstPortShort);
334 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
335 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700336 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000337
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700338 counterMyFlowPaths++;
339
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700340 //
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700341 // NOTE: Using here the regular getDatabaseShortestPath()
342 // method won't work here, because that method calls
343 // internally "conn.endTx(Transaction.COMMIT)", and that
344 // will invalidate all handlers to the Titan database.
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700345 // If we want to experiment with calling here
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700346 // getDatabaseShortestPath(), we need to refactor that code
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700347 // to avoid closing the transaction.
348 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700349 DataPath dataPath =
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700350 topologyNetService.getTopologyShortestPath(
351 topology,
352 srcSwitchPort,
353 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000354 if (dataPath == null) {
355 // We need the DataPath to compare the paths
356 dataPath = new DataPath();
357 dataPath.setSrcPort(srcSwitchPort);
358 dataPath.setDstPort(dstSwitchPort);
359 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700360 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000361
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700362 String newDataPathSummaryStr = dataPath.dataPathSummary();
363 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
364 continue; // Nothing changed
365
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700366 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700367 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000368
369 //
370 // Delete all leftover Flows marked for deletion from the
371 // Network MAP.
372 //
373 while (! deleteFlows.isEmpty()) {
374 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700375 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000376 }
377
Pavlin Radoslavov15954d42013-10-19 15:29:04 -0700378 topologyNetService.dropTopology(topology);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700379
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700380 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700381
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700382 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700383 double rate = 0.0;
384 if (estimatedTime > 0)
385 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700386 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700387 counterAllFlowPaths + " MyFlowPaths: " +
388 counterMyFlowPaths + " in " +
389 (double)estimatedTime / 1000000000 + " sec: " +
390 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700391 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800392 }
393 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700394
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800395
admin944ef4f2013-10-08 17:48:37 -0700396 /**
397 * Initialize the Flow Manager.
398 *
399 * @param conf the Graph Database configuration string.
400 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800401 @Override
402 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700403 op = new GraphDBOperation(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800404 }
405
admin944ef4f2013-10-08 17:48:37 -0700406 /**
407 * Shutdown the Flow Manager operation.
408 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800409 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700410 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800411 }
412
admin944ef4f2013-10-08 17:48:37 -0700413 /**
414 * Shutdown the Flow Manager operation.
415 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800416 @Override
417 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700418 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800419 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800420
admin944ef4f2013-10-08 17:48:37 -0700421 /**
422 * Get the collection of offered module services.
423 *
424 * @return the collection of offered module services.
425 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800426 @Override
427 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
428 Collection<Class<? extends IFloodlightService>> l =
429 new ArrayList<Class<? extends IFloodlightService>>();
430 l.add(IFlowService.class);
431 return l;
432 }
433
admin944ef4f2013-10-08 17:48:37 -0700434 /**
435 * Get the collection of implemented services.
436 *
437 * @return the collection of implemented services.
438 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800439 @Override
440 public Map<Class<? extends IFloodlightService>, IFloodlightService>
441 getServiceImpls() {
442 Map<Class<? extends IFloodlightService>,
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700443 IFloodlightService> m =
444 new HashMap<Class<? extends IFloodlightService>,
445 IFloodlightService>();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800446 m.put(IFlowService.class, this);
447 return m;
448 }
449
admin944ef4f2013-10-08 17:48:37 -0700450 /**
451 * Get the collection of modules this module depends on.
452 *
453 * @return the collection of modules this module depends on.
454 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800455 @Override
456 public Collection<Class<? extends IFloodlightService>>
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700457 getModuleDependencies() {
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800458 Collection<Class<? extends IFloodlightService>> l =
459 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800460 l.add(IFloodlightProviderService.class);
Pavlin Radoslavove9a3ef92013-10-18 18:46:45 -0700461 l.add(INetworkGraphService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700462 l.add(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 l.add(IRestApiService.class);
464 return l;
465 }
466
admin944ef4f2013-10-08 17:48:37 -0700467 /**
468 * Initialize the module.
469 *
470 * @param context the module context to use for the initialization.
471 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800472 @Override
473 public void init(FloodlightModuleContext context)
474 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700475 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800476 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700477 topologyNetService = context.getServiceImpl(ITopologyNetService.class);
478 datagridService = context.getServiceImpl(IDatagridService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800479 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavov05378272013-10-19 23:23:05 -0700480
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800481 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
482 EnumSet.of(OFType.FLOW_MOD),
483 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700484
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700485 this.init("");
486
admin944ef4f2013-10-08 17:48:37 -0700487 mapReaderScheduler = Executors.newScheduledThreadPool(1);
488 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800489 }
490
admin944ef4f2013-10-08 17:48:37 -0700491 /**
492 * Get the next Flow Entry ID to use.
493 *
494 * @return the next Flow Entry ID to use.
495 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700496 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000497 //
498 // Generate the next Flow Entry ID.
499 // NOTE: For now, the higher 32 bits are random, and
500 // the lower 32 bits are sequential.
501 // In the future, we need a better allocation mechanism.
502 //
503 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
504 nextFlowEntryIdPrefix = randomGenerator.nextInt();
505 nextFlowEntryIdSuffix = 0;
506 } else {
507 nextFlowEntryIdSuffix++;
508 }
509 long result = (long)nextFlowEntryIdPrefix << 32;
510 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
511 return result;
512 }
513
admin944ef4f2013-10-08 17:48:37 -0700514 /**
515 * Startup module operation.
516 *
517 * @param context the module context to use for the startup.
518 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800519 @Override
520 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700521 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700522
admin944ef4f2013-10-08 17:48:37 -0700523 // Initialize the Flow Entry ID generator
524 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700525
admin944ef4f2013-10-08 17:48:37 -0700526 mapReaderScheduler.scheduleAtFixedRate(
527 mapReader, 3, 3, TimeUnit.SECONDS);
528 shortestPathReconcileScheduler.scheduleAtFixedRate(
529 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800530 }
531
532 /**
533 * Add a flow.
534 *
535 * Internally, ONOS will automatically register the installer for
536 * receiving Flow Path Notifications for that path.
537 *
538 * @param flowPath the Flow Path to install.
539 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700540 * @param dataPathSummaryStr the data path summary string if the added
541 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800542 * @return true on success, otherwise false.
543 */
544 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700545 public boolean addFlow(FlowPath flowPath, FlowId flowId,
546 String dataPathSummaryStr) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800547 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000548 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800549 try {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700550 if ((flowObj = op.searchFlowPath(flowPath.flowId())) != null) {
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000551 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800552 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700553 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800554 }
555 } catch (Exception e) {
556 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700557 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000558
559 StringWriter sw = new StringWriter();
560 e.printStackTrace(new PrintWriter(sw));
561 String stacktrace = sw.toString();
562
563 log.error(":addFlow FlowId:{} failed: {}",
564 flowPath.flowId().toString(),
565 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800566 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700567 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000568 log.error(":addFlow FlowId:{} failed: Flow object not created",
569 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700570 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800571 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700572 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800573
574 //
575 // Set the Flow key:
576 // - flowId
577 //
578 flowObj.setFlowId(flowPath.flowId().toString());
579 flowObj.setType("flow");
580
581 //
582 // Set the Flow attributes:
583 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700584 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800585 // - flowPath.dataPath().srcPort()
586 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700587 // - flowPath.matchSrcMac()
588 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700589 // - flowPath.matchEthernetFrameType()
590 // - flowPath.matchVlanId()
591 // - flowPath.matchVlanPriority()
592 // - flowPath.matchSrcIPv4Net()
593 // - flowPath.matchDstIPv4Net()
594 // - flowPath.matchIpProto()
595 // - flowPath.matchIpToS()
596 // - flowPath.matchSrcTcpUdpPort()
597 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700598 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800599 //
600 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700601 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800602 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
603 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
604 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
605 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700606 if (flowPath.flowEntryMatch().matchSrcMac()) {
607 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
608 }
609 if (flowPath.flowEntryMatch().matchDstMac()) {
610 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
611 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700612 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
613 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
614 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700615 if (flowPath.flowEntryMatch().matchVlanId()) {
616 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
617 }
618 if (flowPath.flowEntryMatch().matchVlanPriority()) {
619 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
620 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700621 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
622 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
623 }
624 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
625 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
626 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700627 if (flowPath.flowEntryMatch().matchIpProto()) {
628 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700629 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700630 if (flowPath.flowEntryMatch().matchIpToS()) {
631 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
632 }
633 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
634 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
635 }
636 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
637 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700638 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700639 if (! flowPath.flowEntryActions().actions().isEmpty()) {
640 flowObj.setActions(flowPath.flowEntryActions().toString());
641 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700643 if (dataPathSummaryStr != null) {
644 flowObj.setDataPathSummary(dataPathSummaryStr);
645 } else {
646 flowObj.setDataPathSummary("");
647 }
648
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000649 if (found)
650 flowObj.setUserState("FE_USER_MODIFY");
651 else
652 flowObj.setUserState("FE_USER_ADD");
653
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800654 // Flow edges:
655 // HeadFE
656
657
658 //
659 // Flow Entries:
660 // flowPath.dataPath().flowEntries()
661 //
662 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700663 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700664 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800665 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700666 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800667 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700668 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800669
670 //
671 // TODO: We need a proper Flow ID allocation mechanism.
672 //
673 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700674
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800675 return true;
676 }
677
678 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700679 * Add a flow entry to the Network MAP.
680 *
681 * @param flowObj the corresponding Flow Path object for the Flow Entry.
682 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700683 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700684 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700685 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700686 // Flow edges
687 // HeadFE (TODO)
688
689 //
690 // Assign the FlowEntry ID.
691 //
692 if ((flowEntry.flowEntryId() == null) ||
693 (flowEntry.flowEntryId().value() == 0)) {
694 long id = getNextFlowEntryId();
695 flowEntry.setFlowEntryId(new FlowEntryId(id));
696 }
697
698 IFlowEntry flowEntryObj = null;
699 boolean found = false;
700 try {
701 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700702 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700703 found = true;
704 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700705 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700706 }
707 } catch (Exception e) {
708 log.error(":addFlow FlowEntryId:{} failed",
709 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700710 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700711 }
712 if (flowEntryObj == null) {
713 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
714 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700715 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700716 }
717
718 //
719 // Set the Flow Entry key:
720 // - flowEntry.flowEntryId()
721 //
722 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
723 flowEntryObj.setType("flow_entry");
724
725 //
726 // Set the Flow Entry Edges and attributes:
727 // - Switch edge
728 // - InPort edge
729 // - OutPort edge
730 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700731 // - flowEntry.dpid()
732 // - flowEntry.flowEntryUserState()
733 // - flowEntry.flowEntrySwitchState()
734 // - flowEntry.flowEntryErrorState()
735 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700736 // - flowEntry.matchSrcMac()
737 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700738 // - flowEntry.matchEthernetFrameType()
739 // - flowEntry.matchVlanId()
740 // - flowEntry.matchVlanPriority()
741 // - flowEntry.matchSrcIPv4Net()
742 // - flowEntry.matchDstIPv4Net()
743 // - flowEntry.matchIpProto()
744 // - flowEntry.matchIpToS()
745 // - flowEntry.matchSrcTcpUdpPort()
746 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700747 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700748 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700749 //
admin944ef4f2013-10-08 17:48:37 -0700750 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700751 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
752 flowEntryObj.setSwitch(sw);
753 if (flowEntry.flowEntryMatch().matchInPort()) {
754 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700755 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700756 flowEntry.flowEntryMatch().inPort().value());
757 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
758 flowEntryObj.setInPort(inport);
759 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700760 if (flowEntry.flowEntryMatch().matchSrcMac()) {
761 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
762 }
763 if (flowEntry.flowEntryMatch().matchDstMac()) {
764 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
765 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700766 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
767 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
768 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700769 if (flowEntry.flowEntryMatch().matchVlanId()) {
770 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
771 }
772 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
773 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
774 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700775 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
776 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
777 }
778 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
779 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
780 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700781 if (flowEntry.flowEntryMatch().matchIpProto()) {
782 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700783 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700784 if (flowEntry.flowEntryMatch().matchIpToS()) {
785 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
786 }
787 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
788 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
789 }
790 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
791 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700792 }
793
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700794 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700795 if (fa.actionOutput() != null) {
796 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700797 op.searchPort(flowEntry.dpid().toString(),
798 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700799 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700800 flowEntryObj.setOutPort(outport);
801 }
802 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700803 if (! flowEntry.flowEntryActions().isEmpty()) {
804 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
805 }
806
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700807 // TODO: Hacks with hard-coded state names!
808 if (found)
809 flowEntryObj.setUserState("FE_USER_MODIFY");
810 else
811 flowEntryObj.setUserState("FE_USER_ADD");
812 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
813 //
814 // TODO: Take care of the FlowEntryErrorState.
815 //
816
817 // Flow Entries edges:
818 // Flow
819 // NextFE (TODO)
820 if (! found) {
821 flowObj.addFlowEntry(flowEntryObj);
822 flowEntryObj.setFlow(flowObj);
823 }
824
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700825 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700826 }
827
828 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000829 * Delete all previously added flows.
830 *
831 * @return true on success, otherwise false.
832 */
833 @Override
834 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000835 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
836 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000837
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000838 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700839 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000840 for (IFlowPath flowPathObj : allFlowPaths) {
841 if (flowPathObj == null)
842 continue;
843 String flowIdStr = flowPathObj.getFlowId();
844 if (flowIdStr == null)
845 continue;
846 FlowId flowId = new FlowId(flowIdStr);
847 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000848 }
849
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000850 // Delete all flows one-by-one
851 for (FlowId flowId : concurrentAllFlowIds)
852 deleteFlow(flowId);
853
854 /*
855 * TODO: A faster mechanism to delete the Flow Paths by using
856 * a number of threads. Commented-out for now.
857 */
858 /*
859 //
860 // Create the threads to delete the Flow Paths
861 //
Yuta HIGUCHI6f0e4392013-10-09 17:43:34 -0700862 List<Thread> threads = new LinkedList<Thread>();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000863 for (int i = 0; i < 10; i++) {
864 Thread thread = new Thread(new Runnable() {
865 @Override
866 public void run() {
867 while (true) {
868 FlowId flowId = concurrentAllFlowIds.poll();
869 if (flowId == null)
870 return;
871 deleteFlow(flowId);
872 }
873 }}, "Delete All Flow Paths");
874 threads.add(thread);
875 }
876
877 // Start processing
878 for (Thread thread : threads) {
879 thread.start();
880 }
881
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000882 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000883 for (Thread thread : threads) {
884 try {
885 thread.join();
886 } catch (InterruptedException e) {
887 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
888 }
889 }
890 */
891
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000892 return true;
893 }
894
895 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800896 * Delete a previously added flow.
897 *
898 * @param flowId the Flow ID of the flow to delete.
899 * @return true on success, otherwise false.
900 */
901 @Override
902 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800903 IFlowPath flowObj = null;
904 //
905 // We just mark the entries for deletion,
906 // and let the switches remove each individual entry after
907 // it has been removed from the switches.
908 //
909 try {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700910 flowObj = op.searchFlowPath(flowId);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800911 } catch (Exception e) {
912 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700913 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800914 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
915 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700916 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700917 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800918 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700919 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800920
921 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000922 // Find and mark for deletion all Flow Entries,
923 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800924 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000925 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800926 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
927 boolean empty = true; // TODO: an ugly hack
928 for (IFlowEntry flowEntryObj : flowEntries) {
929 empty = false;
930 // flowObj.removeFlowEntry(flowEntryObj);
931 // conn.utils().removeFlowEntry(conn, flowEntryObj);
932 flowEntryObj.setUserState("FE_USER_DELETE");
933 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
934 }
935 // Remove from the database empty flows
936 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700937 op.removeFlowPath(flowObj);
938 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800939
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800940 return true;
941 }
942
943 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000944 * Clear the state for all previously added flows.
945 *
946 * @return true on success, otherwise false.
947 */
948 @Override
949 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000950 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000951
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000952 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700953 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000954 for (IFlowPath flowPathObj : allFlowPaths) {
955 if (flowPathObj == null)
956 continue;
957 String flowIdStr = flowPathObj.getFlowId();
958 if (flowIdStr == null)
959 continue;
960 FlowId flowId = new FlowId(flowIdStr);
961 allFlowIds.add(flowId);
962 }
963
964 // Clear all flows one-by-one
965 for (FlowId flowId : allFlowIds) {
966 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000967 }
968
969 return true;
970 }
971
972 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700973 * Clear the state for a previously added flow.
974 *
975 * @param flowId the Flow ID of the flow to clear.
976 * @return true on success, otherwise false.
977 */
978 @Override
979 public boolean clearFlow(FlowId flowId) {
980 IFlowPath flowObj = null;
981 try {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -0700982 flowObj = op.searchFlowPath(flowId);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700983 } catch (Exception e) {
984 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700985 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700986 log.error(":clearFlow FlowId:{} failed", flowId.toString());
987 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700988 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700989 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700990 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700991 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700992
993 //
994 // Remove all Flow Entries
995 //
996 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
997 for (IFlowEntry flowEntryObj : flowEntries) {
998 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700999 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001000 }
1001 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001002 op.removeFlowPath(flowObj);
1003 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001004
1005 return true;
1006 }
1007
1008 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001009 * Get a previously added flow.
1010 *
1011 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001012 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001013 */
1014 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001015 public FlowPath getFlow(FlowId flowId) {
1016 IFlowPath flowObj = null;
1017 try {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001018 flowObj = op.searchFlowPath(flowId);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001019 } catch (Exception e) {
1020 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001021 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001022 log.error(":getFlow FlowId:{} failed", flowId.toString());
1023 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001024 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001025 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001026 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001027 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001028
1029 //
1030 // Extract the Flow state
1031 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001032 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001033 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001034
1035 return flowPath;
1036 }
1037
1038 /**
1039 * Get all previously added flows by a specific installer for a given
1040 * data path endpoints.
1041 *
1042 * @param installerId the Caller ID of the installer of the flow to get.
1043 * @param dataPathEndpoints the data path endpoints of the flow to get.
1044 * @return the Flow Paths if found, otherwise null.
1045 */
1046 @Override
1047 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1048 DataPathEndpoints dataPathEndpoints) {
1049 //
1050 // TODO: The implementation below is not optimal:
1051 // We fetch all flows, and then return only the subset that match
1052 // the query conditions.
1053 // We should use the appropriate Titan/Gremlin query to filter-out
1054 // the flows as appropriate.
1055 //
1056 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001057 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001058
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001059 if (allFlows == null)
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001060 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001061
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001062 for (FlowPath flow : allFlows) {
1063 //
1064 // TODO: String-based comparison is sub-optimal.
1065 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001066 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001067 //
1068 if (! flow.installerId().toString().equals(installerId.toString()))
1069 continue;
1070 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1071 continue;
1072 }
1073 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1074 continue;
1075 }
1076 flowPaths.add(flow);
1077 }
1078
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001079 return flowPaths;
1080 }
1081
1082 /**
1083 * Get all installed flows by all installers for given data path endpoints.
1084 *
1085 * @param dataPathEndpoints the data path endpoints of the flows to get.
1086 * @return the Flow Paths if found, otherwise null.
1087 */
1088 @Override
1089 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1090 //
1091 // TODO: The implementation below is not optimal:
1092 // We fetch all flows, and then return only the subset that match
1093 // the query conditions.
1094 // We should use the appropriate Titan/Gremlin query to filter-out
1095 // the flows as appropriate.
1096 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001097 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1098 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001099
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001100 if (allFlows == null)
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001101 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001102
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001103 for (FlowPath flow : allFlows) {
1104 //
1105 // TODO: String-based comparison is sub-optimal.
1106 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001107 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001108 //
1109 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1110 continue;
1111 }
1112 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1113 continue;
1114 }
1115 flowPaths.add(flow);
1116 }
1117
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001118return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001119 }
1120
1121 /**
admin944ef4f2013-10-08 17:48:37 -07001122 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001123 *
admin944ef4f2013-10-08 17:48:37 -07001124 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001125 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001126 * @return the Flow Paths if found, otherwise null.
1127 */
1128 @Override
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001129 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId,
1130 int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001131
admin944ef4f2013-10-08 17:48:37 -07001132 //
1133 // TODO: The implementation below is not optimal:
1134 // We fetch all flows, and then return only the subset that match
1135 // the query conditions.
1136 // We should use the appropriate Titan/Gremlin query to filter-out
1137 // the flows as appropriate.
1138 //
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001139 ArrayList<IFlowPath> flowPathsWithoutFlowEntries =
1140 getAllFlowsWithoutFlowEntries();
1141
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001142 Collections.sort(flowPathsWithoutFlowEntries,
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001143 new Comparator<IFlowPath>() {
1144 @Override
1145 public int compare(IFlowPath first, IFlowPath second) {
1146 long result =
1147 new FlowId(first.getFlowId()).value()
1148 - new FlowId(second.getFlowId()).value();
1149 if (result > 0) {
1150 return 1;
1151 } else if (result < 0) {
1152 return -1;
1153 } else {
1154 return 0;
1155 }
1156 }
1157 }
1158 );
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001159
Jonathan Hart01f2d272013-04-04 20:03:46 -07001160 return flowPathsWithoutFlowEntries;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001161 }
1162
1163 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001164 * Get all installed flows by all installers.
1165 *
1166 * @return the Flow Paths if found, otherwise null.
1167 */
1168 @Override
1169 public ArrayList<FlowPath> getAllFlows() {
1170 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001171 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001172
1173 try {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001174 flowPathsObj = op.getAllFlowPaths();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001175 } catch (Exception e) {
1176 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001177 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001178 log.error(":getAllFlowPaths failed");
1179 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001180 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001181 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001182 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001183 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001184
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001185 for (IFlowPath flowObj : flowPathsObj) {
1186 //
1187 // Extract the Flow state
1188 //
1189 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001190 if (flowPath != null)
1191 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001192 }
1193
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001194 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001195
1196 return flowPaths;
1197 }
admin944ef4f2013-10-08 17:48:37 -07001198
1199 /**
1200 * Get all Flows information, without the associated Flow Entries.
1201 *
1202 * @return all Flows information, without the associated Flow Entries.
1203 */
1204 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001205 Iterable<IFlowPath> flowPathsObj = null;
1206 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001207
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001208 // TODO: Remove this op.commit() flow, because it is not needed?
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001209 op.commit();
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001210
Jonathan Hart01f2d272013-04-04 20:03:46 -07001211 try {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001212 flowPathsObj = op.getAllFlowPaths();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001213 } catch (Exception e) {
1214 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001215 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001216 log.error(":getAllFlowPaths failed");
1217 }
1218 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001219 return flowPathsObjArray; // No Flows found
Jonathan Hart01f2d272013-04-04 20:03:46 -07001220 }
1221
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001222 for (IFlowPath flowObj : flowPathsObj)
1223 flowPathsObjArray.add(flowObj);
Jonathan Hart01f2d272013-04-04 20:03:46 -07001224
Pavlin Radoslavov50e532e2013-10-20 02:07:51 -07001225 // conn.endTx(Transaction.COMMIT);
Jonathan Hart01f2d272013-04-04 20:03:46 -07001226
1227 return flowPathsObjArray;
1228 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001229
1230 /**
1231 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1232 *
1233 * @param flowObj the object to extract the Flow Path State from.
1234 * @return the extracted Flow Path State.
1235 */
1236 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001237 //
1238 // Extract the Flow state
1239 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001240 String flowIdStr = flowObj.getFlowId();
1241 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001242 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001243 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001244 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001245 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001246 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001247
1248 if ((flowIdStr == null) ||
1249 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001250 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001251 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001252 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001253 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001254 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001255 // TODO: A work-around, becauuse of some bogus database objects
1256 return null;
1257 }
1258
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001259 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001260 flowPath.setFlowId(new FlowId(flowIdStr));
1261 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001262 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001263 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001264 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001265 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001266 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001267 //
1268 // Extract the match conditions common for all Flow Entries
1269 //
1270 {
1271 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001272 String matchSrcMac = flowObj.getMatchSrcMac();
1273 if (matchSrcMac != null)
1274 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1275 String matchDstMac = flowObj.getMatchDstMac();
1276 if (matchDstMac != null)
1277 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001278 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1279 if (matchEthernetFrameType != null)
1280 match.enableEthernetFrameType(matchEthernetFrameType);
1281 Short matchVlanId = flowObj.getMatchVlanId();
1282 if (matchVlanId != null)
1283 match.enableVlanId(matchVlanId);
1284 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1285 if (matchVlanPriority != null)
1286 match.enableVlanPriority(matchVlanPriority);
1287 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1288 if (matchSrcIPv4Net != null)
1289 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1290 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1291 if (matchDstIPv4Net != null)
1292 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1293 Byte matchIpProto = flowObj.getMatchIpProto();
1294 if (matchIpProto != null)
1295 match.enableIpProto(matchIpProto);
1296 Byte matchIpToS = flowObj.getMatchIpToS();
1297 if (matchIpToS != null)
1298 match.enableIpToS(matchIpToS);
1299 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1300 if (matchSrcTcpUdpPort != null)
1301 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1302 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1303 if (matchDstTcpUdpPort != null)
1304 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1305
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001306 flowPath.setFlowEntryMatch(match);
1307 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001308 //
1309 // Extract the actions for the first Flow Entry
1310 //
1311 {
1312 String actionsStr = flowObj.getActions();
1313 if (actionsStr != null) {
1314 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1315 flowPath.setFlowEntryActions(flowEntryActions);
1316 }
1317 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001318
1319 //
1320 // Extract all Flow Entries
1321 //
1322 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1323 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001324 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1325 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001326 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001327 flowPath.dataPath().flowEntries().add(flowEntry);
1328 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001329
1330 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001331 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001332
1333 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001334 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1335 *
1336 * @param flowEntryObj the object to extract the Flow Entry State from.
1337 * @return the extracted Flow Entry State.
1338 */
1339 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1340 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1341 String switchDpidStr = flowEntryObj.getSwitchDpid();
1342 String userState = flowEntryObj.getUserState();
1343 String switchState = flowEntryObj.getSwitchState();
1344
1345 if ((flowEntryIdStr == null) ||
1346 (switchDpidStr == null) ||
1347 (userState == null) ||
1348 (switchState == null)) {
1349 // TODO: A work-around, becauuse of some bogus database objects
1350 return null;
1351 }
1352
1353 FlowEntry flowEntry = new FlowEntry();
1354 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1355 flowEntry.setDpid(new Dpid(switchDpidStr));
1356
1357 //
1358 // Extract the match conditions
1359 //
1360 FlowEntryMatch match = new FlowEntryMatch();
1361 Short matchInPort = flowEntryObj.getMatchInPort();
1362 if (matchInPort != null)
1363 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001364 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1365 if (matchSrcMac != null)
1366 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1367 String matchDstMac = flowEntryObj.getMatchDstMac();
1368 if (matchDstMac != null)
1369 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001370 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1371 if (matchEthernetFrameType != null)
1372 match.enableEthernetFrameType(matchEthernetFrameType);
1373 Short matchVlanId = flowEntryObj.getMatchVlanId();
1374 if (matchVlanId != null)
1375 match.enableVlanId(matchVlanId);
1376 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1377 if (matchVlanPriority != null)
1378 match.enableVlanPriority(matchVlanPriority);
1379 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1380 if (matchSrcIPv4Net != null)
1381 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1382 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1383 if (matchDstIPv4Net != null)
1384 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1385 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1386 if (matchIpProto != null)
1387 match.enableIpProto(matchIpProto);
1388 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1389 if (matchIpToS != null)
1390 match.enableIpToS(matchIpToS);
1391 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1392 if (matchSrcTcpUdpPort != null)
1393 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1394 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1395 if (matchDstTcpUdpPort != null)
1396 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001397 flowEntry.setFlowEntryMatch(match);
1398
1399 //
1400 // Extract the actions
1401 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001402 FlowEntryActions actions = new FlowEntryActions();
1403 String actionsStr = flowEntryObj.getActions();
1404 if (actionsStr != null)
1405 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001406 flowEntry.setFlowEntryActions(actions);
1407 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1408 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1409 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001410 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001411 //
1412 return flowEntry;
1413 }
1414
1415 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001416 * Add and maintain a shortest-path flow.
1417 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001418 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001419 *
1420 * @param flowPath the Flow Path with the endpoints and the match
1421 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001422 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423 */
1424 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001425 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001426 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001427 // Don't do the shortest path computation here.
1428 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001429 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001430
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001431 // We need the DataPath to populate the Network MAP
1432 DataPath dataPath = new DataPath();
1433 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1434 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001435
1436 //
1437 // Prepare the computed Flow Path
1438 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001439 FlowPath computedFlowPath = new FlowPath();
1440 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1441 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001442 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001443 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001444 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001445 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001446
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001447 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001448 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001449 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001450 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001451
1452 // TODO: Mark the flow for maintenance purpose
1453
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001454 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001455 }
1456
1457 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001458 * Reconcile a flow.
1459 *
1460 * @param flowObj the flow that needs to be reconciliated.
1461 * @param newDataPath the new data path to use.
1462 * @return true on success, otherwise false.
1463 */
1464 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001465
1466 //
1467 // Set the incoming port matching and the outgoing port output
1468 // actions for each flow entry.
1469 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001470 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001471 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1472 // Set the incoming port matching
1473 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1474 flowEntry.setFlowEntryMatch(flowEntryMatch);
1475 flowEntryMatch.enableInPort(flowEntry.inPort());
1476
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001477 //
1478 // Set the actions
1479 //
1480 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1481 //
1482 // If the first Flow Entry, copy the Flow Path actions to it
1483 //
1484 if (idx == 0) {
1485 String actionsStr = flowObj.getActions();
1486 if (actionsStr != null) {
1487 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1488 for (FlowEntryAction action : flowActions.actions())
1489 flowEntryActions.addAction(action);
1490 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001491 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001492 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001493 //
1494 // Add the outgoing port output action
1495 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001496 FlowEntryAction flowEntryAction = new FlowEntryAction();
1497 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001498 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001499 }
1500
1501 //
1502 // Remove the old Flow Entries, and add the new Flow Entries
1503 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001504 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001505 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001506 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001507 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001508 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001509 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001510 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001511 }
1512
1513 //
1514 // Set the Data Path Summary
1515 //
1516 String dataPathSummaryStr = newDataPath.dataPathSummary();
1517 flowObj.setDataPathSummary(dataPathSummaryStr);
1518
1519 return true;
1520 }
1521
1522 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001523 * Reconcile all flows in a set.
1524 *
1525 * @param flowObjSet the set of flows that need to be reconciliated.
1526 */
1527 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1528 if (! flowObjSet.iterator().hasNext())
1529 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001530 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001531 }
1532
1533 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001534 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001535 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001536 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001537 * @param flowObj the flow path object for the flow entry to install.
1538 * @param flowEntryObj the flow entry object to install.
1539 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001540 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001541 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1542 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001543 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1544 if (flowEntryIdStr == null)
1545 return false;
1546 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001547 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001548 if (userState == null)
1549 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001550
1551 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001552 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001553 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001554 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1555 .getMessage(OFType.FLOW_MOD);
1556 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001557
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001558 short flowModCommand = OFFlowMod.OFPFC_ADD;
1559 if (userState.equals("FE_USER_ADD")) {
1560 flowModCommand = OFFlowMod.OFPFC_ADD;
1561 } else if (userState.equals("FE_USER_MODIFY")) {
1562 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1563 } else if (userState.equals("FE_USER_DELETE")) {
1564 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1565 } else {
1566 // Unknown user state. Ignore the entry
1567 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1568 flowEntryId.toString(), userState);
1569 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001570 }
1571
1572 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001573 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001574 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001575 // NOTE: The Flow matching conditions common for all Flow Entries are
1576 // used ONLY if a Flow Entry does NOT have the corresponding matching
1577 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001578 //
1579 OFMatch match = new OFMatch();
1580 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001581
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001582 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001583 Short matchInPort = flowEntryObj.getMatchInPort();
1584 if (matchInPort != null) {
1585 match.setInputPort(matchInPort);
1586 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1587 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001588
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001589 // Match the Source MAC address
1590 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1591 if (matchSrcMac == null)
1592 matchSrcMac = flowObj.getMatchSrcMac();
1593 if (matchSrcMac != null) {
1594 match.setDataLayerSource(matchSrcMac);
1595 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1596 }
1597
1598 // Match the Destination MAC address
1599 String matchDstMac = flowEntryObj.getMatchDstMac();
1600 if (matchDstMac == null)
1601 matchDstMac = flowObj.getMatchDstMac();
1602 if (matchDstMac != null) {
1603 match.setDataLayerDestination(matchDstMac);
1604 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1605 }
1606
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001607 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001608 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1609 if (matchEthernetFrameType == null)
1610 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1611 if (matchEthernetFrameType != null) {
1612 match.setDataLayerType(matchEthernetFrameType);
1613 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1614 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001615
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001616 // Match the VLAN ID
1617 Short matchVlanId = flowEntryObj.getMatchVlanId();
1618 if (matchVlanId == null)
1619 matchVlanId = flowObj.getMatchVlanId();
1620 if (matchVlanId != null) {
1621 match.setDataLayerVirtualLan(matchVlanId);
1622 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1623 }
1624
1625 // Match the VLAN priority
1626 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1627 if (matchVlanPriority == null)
1628 matchVlanPriority = flowObj.getMatchVlanPriority();
1629 if (matchVlanPriority != null) {
1630 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1631 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1632 }
1633
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001634 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001635 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1636 if (matchSrcIPv4Net == null)
1637 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1638 if (matchSrcIPv4Net != null) {
1639 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1640 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001641
1642 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001643 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1644 if (matchDstIPv4Net == null)
1645 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1646 if (matchDstIPv4Net != null) {
1647 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1648 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001649
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001650 // Match the IP protocol
1651 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1652 if (matchIpProto == null)
1653 matchIpProto = flowObj.getMatchIpProto();
1654 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001655 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001656 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001657 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001658
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001659 // Match the IP ToS (DSCP field, 6 bits)
1660 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1661 if (matchIpToS == null)
1662 matchIpToS = flowObj.getMatchIpToS();
1663 if (matchIpToS != null) {
1664 match.setNetworkTypeOfService(matchIpToS);
1665 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1666 }
1667
1668 // Match the Source TCP/UDP port
1669 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1670 if (matchSrcTcpUdpPort == null)
1671 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1672 if (matchSrcTcpUdpPort != null) {
1673 match.setTransportSource(matchSrcTcpUdpPort);
1674 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1675 }
1676
1677 // Match the Destination TCP/UDP port
1678 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1679 if (matchDstTcpUdpPort == null)
1680 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1681 if (matchDstTcpUdpPort != null) {
1682 match.setTransportDestination(matchDstTcpUdpPort);
1683 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001684 }
1685
1686 //
1687 // Fetch the actions
1688 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001689 Short actionOutputPort = null;
1690 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1691 int actionsLen = 0;
1692 FlowEntryActions flowEntryActions = null;
1693 String actionsStr = flowEntryObj.getActions();
1694 if (actionsStr != null)
1695 flowEntryActions = new FlowEntryActions(actionsStr);
1696 for (FlowEntryAction action : flowEntryActions.actions()) {
1697 ActionOutput actionOutput = action.actionOutput();
1698 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1699 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1700 ActionStripVlan actionStripVlan = action.actionStripVlan();
1701 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1702 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1703 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1704 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1705 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1706 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1707 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1708 ActionEnqueue actionEnqueue = action.actionEnqueue();
1709
1710 if (actionOutput != null) {
1711 actionOutputPort = actionOutput.port().value();
1712 // XXX: The max length is hard-coded for now
1713 OFActionOutput ofa =
1714 new OFActionOutput(actionOutput.port().value(),
1715 (short)0xffff);
1716 openFlowActions.add(ofa);
1717 actionsLen += ofa.getLength();
1718 }
1719
1720 if (actionSetVlanId != null) {
1721 OFActionVirtualLanIdentifier ofa =
1722 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1723 openFlowActions.add(ofa);
1724 actionsLen += ofa.getLength();
1725 }
1726
1727 if (actionSetVlanPriority != null) {
1728 OFActionVirtualLanPriorityCodePoint ofa =
1729 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1730 openFlowActions.add(ofa);
1731 actionsLen += ofa.getLength();
1732 }
1733
1734 if (actionStripVlan != null) {
1735 if (actionStripVlan.stripVlan() == true) {
1736 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1737 openFlowActions.add(ofa);
1738 actionsLen += ofa.getLength();
1739 }
1740 }
1741
1742 if (actionSetEthernetSrcAddr != null) {
1743 OFActionDataLayerSource ofa =
1744 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1745 openFlowActions.add(ofa);
1746 actionsLen += ofa.getLength();
1747 }
1748
1749 if (actionSetEthernetDstAddr != null) {
1750 OFActionDataLayerDestination ofa =
1751 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1752 openFlowActions.add(ofa);
1753 actionsLen += ofa.getLength();
1754 }
1755
1756 if (actionSetIPv4SrcAddr != null) {
1757 OFActionNetworkLayerSource ofa =
1758 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1759 openFlowActions.add(ofa);
1760 actionsLen += ofa.getLength();
1761 }
1762
1763 if (actionSetIPv4DstAddr != null) {
1764 OFActionNetworkLayerDestination ofa =
1765 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1766 openFlowActions.add(ofa);
1767 actionsLen += ofa.getLength();
1768 }
1769
1770 if (actionSetIpToS != null) {
1771 OFActionNetworkTypeOfService ofa =
1772 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1773 openFlowActions.add(ofa);
1774 actionsLen += ofa.getLength();
1775 }
1776
1777 if (actionSetTcpUdpSrcPort != null) {
1778 OFActionTransportLayerSource ofa =
1779 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1780 openFlowActions.add(ofa);
1781 actionsLen += ofa.getLength();
1782 }
1783
1784 if (actionSetTcpUdpDstPort != null) {
1785 OFActionTransportLayerDestination ofa =
1786 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1787 openFlowActions.add(ofa);
1788 actionsLen += ofa.getLength();
1789 }
1790
1791 if (actionEnqueue != null) {
1792 OFActionEnqueue ofa =
1793 new OFActionEnqueue(actionEnqueue.port().value(),
1794 actionEnqueue.queueId());
1795 openFlowActions.add(ofa);
1796 actionsLen += ofa.getLength();
1797 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001798 }
1799
1800 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1801 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1802 .setPriority(PRIORITY_DEFAULT)
1803 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1804 .setCookie(cookie)
1805 .setCommand(flowModCommand)
1806 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001807 .setActions(openFlowActions)
1808 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001809 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1810 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1811 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1812 if (actionOutputPort != null)
1813 fm.setOutPort(actionOutputPort);
1814 }
1815
1816 //
1817 // TODO: Set the following flag
1818 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1819 // See method ForwardingBase::pushRoute()
1820 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001821
1822 //
1823 // Write the message to the switch
1824 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001825 log.debug("MEASUREMENT: Installing flow entry " + userState +
1826 " into switch DPID: " +
1827 mySwitch.getStringId() +
1828 " flowEntryId: " + flowEntryId.toString() +
1829 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1830 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1831 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001832 try {
1833 messageDamper.write(mySwitch, fm, null);
1834 mySwitch.flush();
1835 //
1836 // TODO: We should use the OpenFlow Barrier mechanism
1837 // to check for errors, and update the SwitchState
1838 // for a flow entry after the Barrier message is
1839 // is received.
1840 //
1841 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1842 } catch (IOException e) {
1843 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001844 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001845 }
1846
1847 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001848 }
1849
1850 /**
1851 * Install a Flow Entry on a switch.
1852 *
1853 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001854 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001855 * @param flowEntry the flow entry to install.
1856 * @return true on success, otherwise false.
1857 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001858 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1859 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001860 //
1861 // Create the OpenFlow Flow Modification Entry to push
1862 //
1863 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1864 .getMessage(OFType.FLOW_MOD);
1865 long cookie = flowEntry.flowEntryId().value();
1866
1867 short flowModCommand = OFFlowMod.OFPFC_ADD;
1868 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1869 flowModCommand = OFFlowMod.OFPFC_ADD;
1870 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1871 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1872 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1873 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1874 } else {
1875 // Unknown user state. Ignore the entry
1876 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1877 flowEntry.flowEntryId().toString(),
1878 flowEntry.flowEntryUserState());
1879 return false;
1880 }
1881
1882 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001883 // Fetch the match conditions.
1884 //
1885 // NOTE: The Flow matching conditions common for all Flow Entries are
1886 // used ONLY if a Flow Entry does NOT have the corresponding matching
1887 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001888 //
1889 OFMatch match = new OFMatch();
1890 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001891 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1892 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1893
1894 // Match the Incoming Port
1895 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001896 if (matchInPort != null) {
1897 match.setInputPort(matchInPort.value());
1898 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1899 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001900
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001901 // Match the Source MAC address
1902 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1903 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1904 matchSrcMac = flowPathMatch.srcMac();
1905 }
1906 if (matchSrcMac != null) {
1907 match.setDataLayerSource(matchSrcMac.toString());
1908 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1909 }
1910
1911 // Match the Destination MAC address
1912 MACAddress matchDstMac = flowEntryMatch.dstMac();
1913 if ((matchDstMac == null) && (flowPathMatch != null)) {
1914 matchDstMac = flowPathMatch.dstMac();
1915 }
1916 if (matchDstMac != null) {
1917 match.setDataLayerDestination(matchDstMac.toString());
1918 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1919 }
1920
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001921 // Match the Ethernet Frame Type
1922 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1923 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1924 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1925 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001926 if (matchEthernetFrameType != null) {
1927 match.setDataLayerType(matchEthernetFrameType);
1928 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1929 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001930
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001931 // Match the VLAN ID
1932 Short matchVlanId = flowEntryMatch.vlanId();
1933 if ((matchVlanId == null) && (flowPathMatch != null)) {
1934 matchVlanId = flowPathMatch.vlanId();
1935 }
1936 if (matchVlanId != null) {
1937 match.setDataLayerVirtualLan(matchVlanId);
1938 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1939 }
1940
1941 // Match the VLAN priority
1942 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
1943 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
1944 matchVlanPriority = flowPathMatch.vlanPriority();
1945 }
1946 if (matchVlanPriority != null) {
1947 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1948 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1949 }
1950
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001951 // Match the Source IPv4 Network prefix
1952 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1953 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1954 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1955 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001956 if (matchSrcIPv4Net != null) {
1957 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1958 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001959
1960 // Natch the Destination IPv4 Network prefix
1961 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1962 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1963 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1964 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001965 if (matchDstIPv4Net != null) {
1966 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1967 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001968
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001969 // Match the IP protocol
1970 Byte matchIpProto = flowEntryMatch.ipProto();
1971 if ((matchIpProto == null) && (flowPathMatch != null)) {
1972 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001973 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001974 if (matchIpProto != null) {
1975 match.setNetworkProtocol(matchIpProto);
1976 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001977 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001978
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001979 // Match the IP ToS (DSCP field, 6 bits)
1980 Byte matchIpToS = flowEntryMatch.ipToS();
1981 if ((matchIpToS == null) && (flowPathMatch != null)) {
1982 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001983 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001984 if (matchIpToS != null) {
1985 match.setNetworkTypeOfService(matchIpToS);
1986 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1987 }
1988
1989 // Match the Source TCP/UDP port
1990 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
1991 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
1992 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
1993 }
1994 if (matchSrcTcpUdpPort != null) {
1995 match.setTransportSource(matchSrcTcpUdpPort);
1996 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1997 }
1998
1999 // Match the Destination TCP/UDP port
2000 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2001 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2002 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2003 }
2004 if (matchDstTcpUdpPort != null) {
2005 match.setTransportDestination(matchDstTcpUdpPort);
2006 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002007 }
2008
2009 //
2010 // Fetch the actions
2011 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002012 Short actionOutputPort = null;
2013 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2014 int actionsLen = 0;
2015 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002016 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002017 for (FlowEntryAction action : flowEntryActions.actions()) {
2018 ActionOutput actionOutput = action.actionOutput();
2019 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2020 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2021 ActionStripVlan actionStripVlan = action.actionStripVlan();
2022 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2023 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2024 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2025 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2026 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2027 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2028 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2029 ActionEnqueue actionEnqueue = action.actionEnqueue();
2030
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002031 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002032 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002033 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002034 OFActionOutput ofa =
2035 new OFActionOutput(actionOutput.port().value(),
2036 (short)0xffff);
2037 openFlowActions.add(ofa);
2038 actionsLen += ofa.getLength();
2039 }
2040
2041 if (actionSetVlanId != null) {
2042 OFActionVirtualLanIdentifier ofa =
2043 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2044 openFlowActions.add(ofa);
2045 actionsLen += ofa.getLength();
2046 }
2047
2048 if (actionSetVlanPriority != null) {
2049 OFActionVirtualLanPriorityCodePoint ofa =
2050 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2051 openFlowActions.add(ofa);
2052 actionsLen += ofa.getLength();
2053 }
2054
2055 if (actionStripVlan != null) {
2056 if (actionStripVlan.stripVlan() == true) {
2057 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2058 openFlowActions.add(ofa);
2059 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002060 }
2061 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002062
2063 if (actionSetEthernetSrcAddr != null) {
2064 OFActionDataLayerSource ofa =
2065 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2066 openFlowActions.add(ofa);
2067 actionsLen += ofa.getLength();
2068 }
2069
2070 if (actionSetEthernetDstAddr != null) {
2071 OFActionDataLayerDestination ofa =
2072 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2073 openFlowActions.add(ofa);
2074 actionsLen += ofa.getLength();
2075 }
2076
2077 if (actionSetIPv4SrcAddr != null) {
2078 OFActionNetworkLayerSource ofa =
2079 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2080 openFlowActions.add(ofa);
2081 actionsLen += ofa.getLength();
2082 }
2083
2084 if (actionSetIPv4DstAddr != null) {
2085 OFActionNetworkLayerDestination ofa =
2086 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2087 openFlowActions.add(ofa);
2088 actionsLen += ofa.getLength();
2089 }
2090
2091 if (actionSetIpToS != null) {
2092 OFActionNetworkTypeOfService ofa =
2093 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2094 openFlowActions.add(ofa);
2095 actionsLen += ofa.getLength();
2096 }
2097
2098 if (actionSetTcpUdpSrcPort != null) {
2099 OFActionTransportLayerSource ofa =
2100 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2101 openFlowActions.add(ofa);
2102 actionsLen += ofa.getLength();
2103 }
2104
2105 if (actionSetTcpUdpDstPort != null) {
2106 OFActionTransportLayerDestination ofa =
2107 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2108 openFlowActions.add(ofa);
2109 actionsLen += ofa.getLength();
2110 }
2111
2112 if (actionEnqueue != null) {
2113 OFActionEnqueue ofa =
2114 new OFActionEnqueue(actionEnqueue.port().value(),
2115 actionEnqueue.queueId());
2116 openFlowActions.add(ofa);
2117 actionsLen += ofa.getLength();
2118 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002119 }
2120
2121 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2122 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2123 .setPriority(PRIORITY_DEFAULT)
2124 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2125 .setCookie(cookie)
2126 .setCommand(flowModCommand)
2127 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002128 .setActions(openFlowActions)
2129 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2130 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2131 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2132 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2133 if (actionOutputPort != null)
2134 fm.setOutPort(actionOutputPort);
2135 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002136
2137 //
2138 // TODO: Set the following flag
2139 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2140 // See method ForwardingBase::pushRoute()
2141 //
2142
2143 //
2144 // Write the message to the switch
2145 //
2146 try {
2147 messageDamper.write(mySwitch, fm, null);
2148 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002149 //
2150 // TODO: We should use the OpenFlow Barrier mechanism
2151 // to check for errors, and update the SwitchState
2152 // for a flow entry after the Barrier message is
2153 // is received.
2154 //
2155 // TODO: The FlowEntry Object in Titan should be set
2156 // to FE_SWITCH_UPDATED.
2157 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002158 } catch (IOException e) {
2159 log.error("Failure writing flow mod from network map", e);
2160 return false;
2161 }
2162 return true;
2163 }
2164
2165 /**
2166 * Remove a Flow Entry from a switch.
2167 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002168 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002169 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002170 * @param flowEntry the flow entry to remove.
2171 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002172 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002173 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2174 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002175 //
2176 // The installFlowEntry() method implements both installation
2177 // and removal of flow entries.
2178 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002179 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002180 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002181}