blob: ce9941e0219b89e129d1162ba53384a9f5588ef7 [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00004import java.io.PrintWriter;
5import java.io.StringWriter;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.ArrayList;
7import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07008import java.util.Collections;
9import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000012import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000015import java.util.Random;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +000016import java.util.concurrent.ConcurrentLinkedQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.Executors;
18import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070028import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.util.OFMessageDamper;
Pankaj Berde38646d62013-06-21 11:34:04 -070030import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070031import net.onrc.onos.ofcontroller.core.INetMapStorage;
32import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
33import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
36import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070037import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070038import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070039import net.onrc.onos.ofcontroller.util.CallerId;
40import net.onrc.onos.ofcontroller.util.DataPath;
41import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
42import net.onrc.onos.ofcontroller.util.Dpid;
43import net.onrc.onos.ofcontroller.util.FlowEntry;
44import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070045import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
46import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntryId;
48import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
49import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
50import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
51import net.onrc.onos.ofcontroller.util.FlowId;
52import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070053import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070054import net.onrc.onos.ofcontroller.util.IPv4Net;
55import net.onrc.onos.ofcontroller.util.Port;
56import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057
58import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070061import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062import org.openflow.protocol.OFType;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070063import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
admin944ef4f2013-10-08 17:48:37 -070067/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070068 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070069 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070070public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
Toshio Koide9fe1cb22013-06-13 13:51:11 -070072 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080073
74 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070075 protected volatile IFloodlightProviderService floodlightProvider;
76 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070077 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078
79 protected OFMessageDamper messageDamper;
80
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070081 //
82 // TODO: Values copied from elsewhere (class LearningSwitch).
83 // The local copy should go away!
84 //
85 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
86 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
87 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
88 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
89 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000091 // Flow Entry ID generation state
92 private static Random randomGenerator = new Random();
93 private static int nextFlowEntryIdPrefix = 0;
94 private static int nextFlowEntryIdSuffix = 0;
95 private static long nextFlowEntryId = 0;
96
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070097 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070098 private static long measurementFlowId = 100000;
99 private static String measurementFlowIdStr = "0x186a0"; // 100000
100 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700101 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700102
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800103 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800104 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
105
106 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700107 private ScheduledExecutorService mapReaderScheduler;
108 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700109
admin944ef4f2013-10-08 17:48:37 -0700110 /**
111 * Periodic task for reading the Flow Entries and pushing changes
112 * into the switches.
113 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700114 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800115 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700116 try {
117 runImpl();
118 } catch (Exception e) {
119 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700120 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700121 return;
122 }
123 }
124
125 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700126 long startTime = System.nanoTime();
127 int counterAllFlowEntries = 0;
128 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700129
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800130 if (floodlightProvider == null) {
131 log.debug("FloodlightProvider service not found!");
132 return;
133 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000134 Map<Long, IOFSwitch> mySwitches =
135 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700136 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700137 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700138 return;
139 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700140 LinkedList<IFlowEntry> addFlowEntries =
141 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000142 LinkedList<IFlowEntry> deleteFlowEntries =
143 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700144
145 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700146 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700147 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700148 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700149 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000150 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700151 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700152 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700153 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000154
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000155 String dpidStr = flowEntryObj.getSwitchDpid();
156 if (dpidStr == null)
157 continue;
158 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800159 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000160 if (mySwitch == null)
161 continue; // Ignore the entry: not my switch
162
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700163 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700164 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700165 if (flowObj == null)
166 continue; // Should NOT happen
167 if (flowObj.getFlowId() == null)
168 continue; // Invalid entry
169
170 //
171 // NOTE: For now we process the DELETE before the ADD
172 // to cover the more common scenario.
173 // TODO: This is error prone and needs to be fixed!
174 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000175 String userState = flowEntryObj.getUserState();
176 if (userState == null)
177 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700178 if (userState.equals("FE_USER_DELETE")) {
179 // An entry that needs to be deleted.
180 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700181 installFlowEntry(mySwitch, flowObj, flowEntryObj);
182 } else {
183 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700184 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700185 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700186 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700187 // TODO: Commented-out for now
188 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700189 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700190 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700191 processed_measurement_flow = true;
192 }
193 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700194 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700195 }
196
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700197 //
198 // Process the Flow Entries that need to be added
199 //
200 for (IFlowEntry flowEntryObj : addFlowEntries) {
201 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700202 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700203 if (flowObj == null)
204 continue; // Should NOT happen
205 if (flowObj.getFlowId() == null)
206 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700207
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700208 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700209 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000210 if (mySwitch == null)
211 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700212 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800213 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000214
215 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000216 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700217 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000218 //
219 // TODO: We should use the OpenFlow Barrier mechanism
220 // to check for errors, and delete the Flow Entries after the
221 // Barrier message is received.
222 //
223 while (! deleteFlowEntries.isEmpty()) {
224 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
225 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700226 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000227 if (flowObj == null) {
228 log.debug("Did not find FlowPath to be deleted");
229 continue;
230 }
231 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700232 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000233 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700234
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700235 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700236
237 if (processed_measurement_flow) {
238 long estimatedTime =
239 System.nanoTime() - modifiedMeasurementFlowTime;
240 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
241 (double)estimatedTime / 1000000000 + " sec";
242 log.debug(logMsg);
243 }
244
245 long estimatedTime = System.nanoTime() - startTime;
246 double rate = 0.0;
247 if (estimatedTime > 0)
248 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
249 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
250 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
251 counterMyNotUpdatedFlowEntries + " in " +
252 (double)estimatedTime / 1000000000 + " sec: " +
253 rate + " paths/s";
254 log.debug(logMsg);
255 }
256 };
257
admin944ef4f2013-10-08 17:48:37 -0700258 /**
259 * Periodic task for reading the Flow Paths and recomputing the
260 * shortest paths.
261 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700262 final Runnable shortestPathReconcile = new Runnable() {
263 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700264 try {
265 runImpl();
266 } catch (Exception e) {
267 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700268 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700269 return;
270 }
271 }
272
273 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700274 long startTime = System.nanoTime();
275 int counterAllFlowPaths = 0;
276 int counterMyFlowPaths = 0;
277
278 if (floodlightProvider == null) {
279 log.debug("FloodlightProvider service not found!");
280 return;
281 }
282 Map<Long, IOFSwitch> mySwitches =
283 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700284 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700285 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700286 return;
287 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700288 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
289
290 boolean processed_measurement_flow = false;
291
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700292 //
293 // Fetch and recompute the Shortest Path for those
294 // Flow Paths this controller is responsible for.
295 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000296 Map<Long, ?> shortestPathTopo =
297 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700298 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700299 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700300 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700301 if (flowPathObj == null)
302 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700303
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700304 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000305 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700306 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700308 //
309 // Use the source DPID as a heuristic to decide
310 // which controller is responsible for maintaining the
311 // shortest path.
312 // NOTE: This heuristic is error-prone: if the switch
313 // goes away and no controller is responsible for that
314 // switch, then the original Flow Path is not cleaned-up
315 //
316 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
317 if (mySwitch == null)
318 continue; // Ignore: not my responsibility
319
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700320 // Test the Data Path Summary string
321 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
322 if (dataPathSummaryStr == null)
323 continue; // Could be invalid entry?
324 if (dataPathSummaryStr.isEmpty())
325 continue; // No need to maintain this flow
326
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000327 //
328 // Test whether we need to complete the Flow cleanup,
329 // if the Flow has been deleted by the user.
330 //
331 String flowUserState = flowPathObj.getUserState();
332 if ((flowUserState != null)
333 && flowUserState.equals("FE_USER_DELETE")) {
334 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
335 boolean empty = true; // TODO: an ugly hack
336 for (IFlowEntry flowEntryObj : flowEntries) {
337 empty = false;
338 break;
339 }
340 if (empty)
341 deleteFlows.add(flowPathObj);
342 }
343
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000344 // Fetch the fields needed to recompute the shortest path
345 Short srcPortShort = flowPathObj.getSrcPort();
346 String dstDpidStr = flowPathObj.getDstSwitch();
347 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700348 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000349 if ((srcPortShort == null) ||
350 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700351 (dstPortShort == null) ||
352 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000353 continue;
354 }
355
356 Port srcPort = new Port(srcPortShort);
357 Dpid dstDpid = new Dpid(dstDpidStr);
358 Port dstPort = new Port(dstPortShort);
359 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
360 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700361 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000362
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700363 counterMyFlowPaths++;
364
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700365 //
366 // NOTE: Using here the regular getShortestPath() method
367 // won't work here, because that method calls internally
368 // "conn.endTx(Transaction.COMMIT)", and that will
369 // invalidate all handlers to the Titan database.
370 // If we want to experiment with calling here
371 // getShortestPath(), we need to refactor that code
372 // to avoid closing the transaction.
373 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700374 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000375 topoRouteService.getTopoShortestPath(shortestPathTopo,
376 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700377 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000378 if (dataPath == null) {
379 // We need the DataPath to compare the paths
380 dataPath = new DataPath();
381 dataPath.setSrcPort(srcSwitchPort);
382 dataPath.setDstPort(dstSwitchPort);
383 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700384 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000385
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700386 String newDataPathSummaryStr = dataPath.dataPathSummary();
387 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
388 continue; // Nothing changed
389
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700390 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700391 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000392
393 //
394 // Delete all leftover Flows marked for deletion from the
395 // Network MAP.
396 //
397 while (! deleteFlows.isEmpty()) {
398 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700399 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000400 }
401
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000402 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700403
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700404 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700405
406 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700407 long estimatedTime =
408 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700409 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
410 (double)estimatedTime / 1000000000 + " sec";
411 log.debug(logMsg);
412 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700413
414 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700415 double rate = 0.0;
416 if (estimatedTime > 0)
417 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700418 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700419 counterAllFlowPaths + " MyFlowPaths: " +
420 counterMyFlowPaths + " in " +
421 (double)estimatedTime / 1000000000 + " sec: " +
422 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700423 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800424 }
425 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700426
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427
admin944ef4f2013-10-08 17:48:37 -0700428 /**
429 * Initialize the Flow Manager.
430 *
431 * @param conf the Graph Database configuration string.
432 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800433 @Override
434 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700435 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700436 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800437 }
438
admin944ef4f2013-10-08 17:48:37 -0700439 /**
440 * Shutdown the Flow Manager operation.
441 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800442 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700443 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800444 }
445
admin944ef4f2013-10-08 17:48:37 -0700446 /**
447 * Shutdown the Flow Manager operation.
448 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800449 @Override
450 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700451 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800453
admin944ef4f2013-10-08 17:48:37 -0700454 /**
455 * Get the collection of offered module services.
456 *
457 * @return the collection of offered module services.
458 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800459 @Override
460 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
461 Collection<Class<? extends IFloodlightService>> l =
462 new ArrayList<Class<? extends IFloodlightService>>();
463 l.add(IFlowService.class);
464 return l;
465 }
466
admin944ef4f2013-10-08 17:48:37 -0700467 /**
468 * Get the collection of implemented services.
469 *
470 * @return the collection of implemented services.
471 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800472 @Override
473 public Map<Class<? extends IFloodlightService>, IFloodlightService>
474 getServiceImpls() {
475 Map<Class<? extends IFloodlightService>,
476 IFloodlightService> m =
477 new HashMap<Class<? extends IFloodlightService>,
478 IFloodlightService>();
479 m.put(IFlowService.class, this);
480 return m;
481 }
482
admin944ef4f2013-10-08 17:48:37 -0700483 /**
484 * Get the collection of modules this module depends on.
485 *
486 * @return the collection of modules this module depends on.
487 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800488 @Override
489 public Collection<Class<? extends IFloodlightService>>
490 getModuleDependencies() {
491 Collection<Class<? extends IFloodlightService>> l =
492 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800493 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800494 l.add(IRestApiService.class);
495 return l;
496 }
497
admin944ef4f2013-10-08 17:48:37 -0700498 /**
499 * Initialize the module.
500 *
501 * @param context the module context to use for the initialization.
502 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800503 @Override
504 public void init(FloodlightModuleContext context)
505 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700506 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800507 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800508 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
510 EnumSet.of(OFType.FLOW_MOD),
511 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700512
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800513 // TODO: An ugly hack!
514 String conf = "/tmp/cassandra.titan";
515 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700516
admin944ef4f2013-10-08 17:48:37 -0700517 mapReaderScheduler = Executors.newScheduledThreadPool(1);
518 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800519 }
520
admin944ef4f2013-10-08 17:48:37 -0700521 /**
522 * Get the next Flow Entry ID to use.
523 *
524 * @return the next Flow Entry ID to use.
525 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700526 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000527 //
528 // Generate the next Flow Entry ID.
529 // NOTE: For now, the higher 32 bits are random, and
530 // the lower 32 bits are sequential.
531 // In the future, we need a better allocation mechanism.
532 //
533 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
534 nextFlowEntryIdPrefix = randomGenerator.nextInt();
535 nextFlowEntryIdSuffix = 0;
536 } else {
537 nextFlowEntryIdSuffix++;
538 }
539 long result = (long)nextFlowEntryIdPrefix << 32;
540 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
541 return result;
542 }
543
admin944ef4f2013-10-08 17:48:37 -0700544 /**
545 * Startup module operation.
546 *
547 * @param context the module context to use for the startup.
548 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800549 @Override
550 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700551 restApi.addRestletRoutable(new FlowWebRoutable());
Jonathan Hart50a94982013-04-10 14:49:51 -0700552
admin944ef4f2013-10-08 17:48:37 -0700553 // Initialize the Flow Entry ID generator
554 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Jonathan Hart50a94982013-04-10 14:49:51 -0700555
admin944ef4f2013-10-08 17:48:37 -0700556 mapReaderScheduler.scheduleAtFixedRate(
557 mapReader, 3, 3, TimeUnit.SECONDS);
558 shortestPathReconcileScheduler.scheduleAtFixedRate(
559 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800560 }
561
562 /**
563 * Add a flow.
564 *
565 * Internally, ONOS will automatically register the installer for
566 * receiving Flow Path Notifications for that path.
567 *
568 * @param flowPath the Flow Path to install.
569 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700570 * @param dataPathSummaryStr the data path summary string if the added
571 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800572 * @return true on success, otherwise false.
573 */
574 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700575 public boolean addFlow(FlowPath flowPath, FlowId flowId,
576 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700577 /*
578 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700579 if (flowPath.flowId().value() == measurementFlowId) {
580 modifiedMeasurementFlowTime = System.nanoTime();
581 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700582 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800583
584 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000585 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800586 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700587 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800588 != null) {
589 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
590 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000591 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800592 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700593 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800594 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
595 flowPath.flowId().toString());
596 }
597 } catch (Exception e) {
598 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700599 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000600
601 StringWriter sw = new StringWriter();
602 e.printStackTrace(new PrintWriter(sw));
603 String stacktrace = sw.toString();
604
605 log.error(":addFlow FlowId:{} failed: {}",
606 flowPath.flowId().toString(),
607 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800608 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700609 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000610 log.error(":addFlow FlowId:{} failed: Flow object not created",
611 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700612 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800613 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700614 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800615
616 //
617 // Set the Flow key:
618 // - flowId
619 //
620 flowObj.setFlowId(flowPath.flowId().toString());
621 flowObj.setType("flow");
622
623 //
624 // Set the Flow attributes:
625 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700626 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800627 // - flowPath.dataPath().srcPort()
628 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700629 // - flowPath.matchSrcMac()
630 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700631 // - flowPath.matchEthernetFrameType()
632 // - flowPath.matchVlanId()
633 // - flowPath.matchVlanPriority()
634 // - flowPath.matchSrcIPv4Net()
635 // - flowPath.matchDstIPv4Net()
636 // - flowPath.matchIpProto()
637 // - flowPath.matchIpToS()
638 // - flowPath.matchSrcTcpUdpPort()
639 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700640 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800641 //
642 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700643 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800644 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
645 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
646 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
647 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700648 if (flowPath.flowEntryMatch().matchSrcMac()) {
649 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
650 }
651 if (flowPath.flowEntryMatch().matchDstMac()) {
652 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
653 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700654 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
655 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
656 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700657 if (flowPath.flowEntryMatch().matchVlanId()) {
658 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
659 }
660 if (flowPath.flowEntryMatch().matchVlanPriority()) {
661 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
662 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700663 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
664 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
665 }
666 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
667 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
668 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700669 if (flowPath.flowEntryMatch().matchIpProto()) {
670 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700671 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700672 if (flowPath.flowEntryMatch().matchIpToS()) {
673 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
674 }
675 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
676 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
677 }
678 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
679 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700680 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700681 if (! flowPath.flowEntryActions().actions().isEmpty()) {
682 flowObj.setActions(flowPath.flowEntryActions().toString());
683 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800684
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700685 if (dataPathSummaryStr != null) {
686 flowObj.setDataPathSummary(dataPathSummaryStr);
687 } else {
688 flowObj.setDataPathSummary("");
689 }
690
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000691 if (found)
692 flowObj.setUserState("FE_USER_MODIFY");
693 else
694 flowObj.setUserState("FE_USER_ADD");
695
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800696 // Flow edges:
697 // HeadFE
698
699
700 //
701 // Flow Entries:
702 // flowPath.dataPath().flowEntries()
703 //
704 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700705 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700706 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800707 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700708 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800709 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700710 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800711
712 //
713 // TODO: We need a proper Flow ID allocation mechanism.
714 //
715 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700716
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800717 return true;
718 }
719
720 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700721 * Add a flow entry to the Network MAP.
722 *
723 * @param flowObj the corresponding Flow Path object for the Flow Entry.
724 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700725 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700726 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700727 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700728 // Flow edges
729 // HeadFE (TODO)
730
731 //
732 // Assign the FlowEntry ID.
733 //
734 if ((flowEntry.flowEntryId() == null) ||
735 (flowEntry.flowEntryId().value() == 0)) {
736 long id = getNextFlowEntryId();
737 flowEntry.setFlowEntryId(new FlowEntryId(id));
738 }
739
740 IFlowEntry flowEntryObj = null;
741 boolean found = false;
742 try {
743 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700744 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700745 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
746 flowEntry.flowEntryId().toString());
747 found = true;
748 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700749 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700750 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
751 flowEntry.flowEntryId().toString());
752 }
753 } catch (Exception e) {
754 log.error(":addFlow FlowEntryId:{} failed",
755 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700756 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700757 }
758 if (flowEntryObj == null) {
759 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
760 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700761 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700762 }
763
764 //
765 // Set the Flow Entry key:
766 // - flowEntry.flowEntryId()
767 //
768 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
769 flowEntryObj.setType("flow_entry");
770
771 //
772 // Set the Flow Entry Edges and attributes:
773 // - Switch edge
774 // - InPort edge
775 // - OutPort edge
776 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700777 // - flowEntry.dpid()
778 // - flowEntry.flowEntryUserState()
779 // - flowEntry.flowEntrySwitchState()
780 // - flowEntry.flowEntryErrorState()
781 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700782 // - flowEntry.matchSrcMac()
783 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700784 // - flowEntry.matchEthernetFrameType()
785 // - flowEntry.matchVlanId()
786 // - flowEntry.matchVlanPriority()
787 // - flowEntry.matchSrcIPv4Net()
788 // - flowEntry.matchDstIPv4Net()
789 // - flowEntry.matchIpProto()
790 // - flowEntry.matchIpToS()
791 // - flowEntry.matchSrcTcpUdpPort()
792 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700793 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700794 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700795 //
admin944ef4f2013-10-08 17:48:37 -0700796 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700797 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
798 flowEntryObj.setSwitch(sw);
799 if (flowEntry.flowEntryMatch().matchInPort()) {
800 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700801 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700802 flowEntry.flowEntryMatch().inPort().value());
803 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
804 flowEntryObj.setInPort(inport);
805 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700806 if (flowEntry.flowEntryMatch().matchSrcMac()) {
807 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
808 }
809 if (flowEntry.flowEntryMatch().matchDstMac()) {
810 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
811 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700812 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
813 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
814 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700815 if (flowEntry.flowEntryMatch().matchVlanId()) {
816 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
817 }
818 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
819 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
820 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700821 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
822 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
823 }
824 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
825 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
826 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700827 if (flowEntry.flowEntryMatch().matchIpProto()) {
828 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700829 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700830 if (flowEntry.flowEntryMatch().matchIpToS()) {
831 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
832 }
833 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
834 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
835 }
836 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
837 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700838 }
839
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700840 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700841 if (fa.actionOutput() != null) {
842 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700843 op.searchPort(flowEntry.dpid().toString(),
844 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700845 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700846 flowEntryObj.setOutPort(outport);
847 }
848 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700849 if (! flowEntry.flowEntryActions().isEmpty()) {
850 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
851 }
852
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700853 // TODO: Hacks with hard-coded state names!
854 if (found)
855 flowEntryObj.setUserState("FE_USER_MODIFY");
856 else
857 flowEntryObj.setUserState("FE_USER_ADD");
858 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
859 //
860 // TODO: Take care of the FlowEntryErrorState.
861 //
862
863 // Flow Entries edges:
864 // Flow
865 // NextFE (TODO)
866 if (! found) {
867 flowObj.addFlowEntry(flowEntryObj);
868 flowEntryObj.setFlow(flowObj);
869 }
870
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700871 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700872 }
873
874 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000875 * Delete all previously added flows.
876 *
877 * @return true on success, otherwise false.
878 */
879 @Override
880 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000881 List<Thread> threads = new LinkedList<Thread>();
882 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
883 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000884
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000885 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700886 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000887 for (IFlowPath flowPathObj : allFlowPaths) {
888 if (flowPathObj == null)
889 continue;
890 String flowIdStr = flowPathObj.getFlowId();
891 if (flowIdStr == null)
892 continue;
893 FlowId flowId = new FlowId(flowIdStr);
894 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000895 }
896
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000897 // Delete all flows one-by-one
898 for (FlowId flowId : concurrentAllFlowIds)
899 deleteFlow(flowId);
900
901 /*
902 * TODO: A faster mechanism to delete the Flow Paths by using
903 * a number of threads. Commented-out for now.
904 */
905 /*
906 //
907 // Create the threads to delete the Flow Paths
908 //
909 for (int i = 0; i < 10; i++) {
910 Thread thread = new Thread(new Runnable() {
911 @Override
912 public void run() {
913 while (true) {
914 FlowId flowId = concurrentAllFlowIds.poll();
915 if (flowId == null)
916 return;
917 deleteFlow(flowId);
918 }
919 }}, "Delete All Flow Paths");
920 threads.add(thread);
921 }
922
923 // Start processing
924 for (Thread thread : threads) {
925 thread.start();
926 }
927
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000928 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000929 for (Thread thread : threads) {
930 try {
931 thread.join();
932 } catch (InterruptedException e) {
933 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
934 }
935 }
936 */
937
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000938 return true;
939 }
940
941 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800942 * Delete a previously added flow.
943 *
944 * @param flowId the Flow ID of the flow to delete.
945 * @return true on success, otherwise false.
946 */
947 @Override
948 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700949 /*
950 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700951 if (flowId.value() == measurementFlowId) {
952 modifiedMeasurementFlowTime = System.nanoTime();
953 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700954 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700955
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800956 IFlowPath flowObj = null;
957 //
958 // We just mark the entries for deletion,
959 // and let the switches remove each individual entry after
960 // it has been removed from the switches.
961 //
962 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700963 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800964 != null) {
965 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
966 flowId.toString());
967 } else {
968 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
969 flowId.toString());
970 }
971 } catch (Exception e) {
972 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700973 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800974 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
975 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700976 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700977 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800978 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700979 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800980
981 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000982 // Find and mark for deletion all Flow Entries,
983 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800984 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000985 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800986 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
987 boolean empty = true; // TODO: an ugly hack
988 for (IFlowEntry flowEntryObj : flowEntries) {
989 empty = false;
990 // flowObj.removeFlowEntry(flowEntryObj);
991 // conn.utils().removeFlowEntry(conn, flowEntryObj);
992 flowEntryObj.setUserState("FE_USER_DELETE");
993 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
994 }
995 // Remove from the database empty flows
996 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700997 op.removeFlowPath(flowObj);
998 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800999
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001000 return true;
1001 }
1002
1003 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001004 * Clear the state for all previously added flows.
1005 *
1006 * @return true on success, otherwise false.
1007 */
1008 @Override
1009 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001010 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001011
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001012 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001013 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001014 for (IFlowPath flowPathObj : allFlowPaths) {
1015 if (flowPathObj == null)
1016 continue;
1017 String flowIdStr = flowPathObj.getFlowId();
1018 if (flowIdStr == null)
1019 continue;
1020 FlowId flowId = new FlowId(flowIdStr);
1021 allFlowIds.add(flowId);
1022 }
1023
1024 // Clear all flows one-by-one
1025 for (FlowId flowId : allFlowIds) {
1026 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001027 }
1028
1029 return true;
1030 }
1031
1032 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001033 * Clear the state for a previously added flow.
1034 *
1035 * @param flowId the Flow ID of the flow to clear.
1036 * @return true on success, otherwise false.
1037 */
1038 @Override
1039 public boolean clearFlow(FlowId flowId) {
1040 IFlowPath flowObj = null;
1041 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001042 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001043 != null) {
1044 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1045 flowId.toString());
1046 } else {
1047 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1048 flowId.toString());
1049 }
1050 } catch (Exception e) {
1051 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001052 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001053 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1054 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001055 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001056 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001057 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001058 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001059
1060 //
1061 // Remove all Flow Entries
1062 //
1063 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1064 for (IFlowEntry flowEntryObj : flowEntries) {
1065 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001066 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001067 }
1068 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001069 op.removeFlowPath(flowObj);
1070 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001071
1072 return true;
1073 }
1074
1075 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001076 * Get a previously added flow.
1077 *
1078 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001079 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001080 */
1081 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001082 public FlowPath getFlow(FlowId flowId) {
1083 IFlowPath flowObj = null;
1084 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001085 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001086 != null) {
1087 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1088 flowId.toString());
1089 } else {
1090 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1091 flowId.toString());
1092 }
1093 } catch (Exception e) {
1094 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001095 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001096 log.error(":getFlow FlowId:{} failed", flowId.toString());
1097 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001098 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001099 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001100 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001101 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001102
1103 //
1104 // Extract the Flow state
1105 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001106 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001107 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001108
1109 return flowPath;
1110 }
1111
1112 /**
1113 * Get all previously added flows by a specific installer for a given
1114 * data path endpoints.
1115 *
1116 * @param installerId the Caller ID of the installer of the flow to get.
1117 * @param dataPathEndpoints the data path endpoints of the flow to get.
1118 * @return the Flow Paths if found, otherwise null.
1119 */
1120 @Override
1121 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1122 DataPathEndpoints dataPathEndpoints) {
1123 //
1124 // TODO: The implementation below is not optimal:
1125 // We fetch all flows, and then return only the subset that match
1126 // the query conditions.
1127 // We should use the appropriate Titan/Gremlin query to filter-out
1128 // the flows as appropriate.
1129 //
1130 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001131 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001132
1133 if (allFlows == null) {
1134 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001135 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001136 }
1137
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001138 for (FlowPath flow : allFlows) {
1139 //
1140 // TODO: String-based comparison is sub-optimal.
1141 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001142 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001143 //
1144 if (! flow.installerId().toString().equals(installerId.toString()))
1145 continue;
1146 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1147 continue;
1148 }
1149 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1150 continue;
1151 }
1152 flowPaths.add(flow);
1153 }
1154
1155 if (flowPaths.isEmpty()) {
1156 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001157 } else {
1158 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1159 }
1160
1161 return flowPaths;
1162 }
1163
1164 /**
1165 * Get all installed flows by all installers for given data path endpoints.
1166 *
1167 * @param dataPathEndpoints the data path endpoints of the flows to get.
1168 * @return the Flow Paths if found, otherwise null.
1169 */
1170 @Override
1171 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1172 //
1173 // TODO: The implementation below is not optimal:
1174 // We fetch all flows, and then return only the subset that match
1175 // the query conditions.
1176 // We should use the appropriate Titan/Gremlin query to filter-out
1177 // the flows as appropriate.
1178 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001179 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1180 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001181
1182 if (allFlows == null) {
1183 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001184 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001185 }
1186
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001187 for (FlowPath flow : allFlows) {
1188 //
1189 // TODO: String-based comparison is sub-optimal.
1190 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001191 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001192 //
1193 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1194 continue;
1195 }
1196 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1197 continue;
1198 }
1199 flowPaths.add(flow);
1200 }
1201
1202 if (flowPaths.isEmpty()) {
1203 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001204 } else {
1205 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1206 }
1207
1208 return flowPaths;
1209 }
1210
1211 /**
admin944ef4f2013-10-08 17:48:37 -07001212 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001213 *
admin944ef4f2013-10-08 17:48:37 -07001214 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001215 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001216 * @return the Flow Paths if found, otherwise null.
1217 */
1218 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001219 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001220
admin944ef4f2013-10-08 17:48:37 -07001221 //
1222 // TODO: The implementation below is not optimal:
1223 // We fetch all flows, and then return only the subset that match
1224 // the query conditions.
1225 // We should use the appropriate Titan/Gremlin query to filter-out
1226 // the flows as appropriate.
1227 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001228 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001229
Jonathan Hart01f2d272013-04-04 20:03:46 -07001230 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1231
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001232 Collections.sort(flowPathsWithoutFlowEntries,
1233 new Comparator<IFlowPath>(){
1234 @Override
1235 public int compare(IFlowPath first, IFlowPath second) {
1236 // TODO Auto-generated method stub
1237 long result = new FlowId(first.getFlowId()).value()
1238 - new FlowId(second.getFlowId()).value();
1239 if (result > 0) return 1;
1240 else if (result < 0) return -1;
1241 else return 0;
1242 }
1243 }
1244 );
1245
Jonathan Hart01f2d272013-04-04 20:03:46 -07001246 return flowPathsWithoutFlowEntries;
1247
1248 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001249 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001250
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001251 if (allFlows == null) {
1252 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001253 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001254 }
1255
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001256 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001257
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001258 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001259 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001260
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001261 // start from desired flowId
1262 if (flow.flowId().value() < flowId.value()) {
1263 continue;
1264 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001265
1266 // Summarize by making null flow entry fields that are not relevant to report
1267 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1268 flowEntry.setFlowEntryActions(null);
1269 flowEntry.setFlowEntryMatch(null);
1270 }
1271
1272 flowPaths.add(flow);
1273 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1274 break;
1275 }
1276 }
1277
1278 if (flowPaths.isEmpty()) {
1279 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001280 } else {
1281 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1282 }
1283
1284 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001285 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001286 }
1287
1288 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001289 * Get all installed flows by all installers.
1290 *
1291 * @return the Flow Paths if found, otherwise null.
1292 */
1293 @Override
1294 public ArrayList<FlowPath> getAllFlows() {
1295 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001296 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001297
1298 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001299 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001300 log.debug("Get all FlowPaths: found FlowPaths");
1301 } else {
1302 log.debug("Get all FlowPaths: no FlowPaths found");
1303 }
1304 } catch (Exception e) {
1305 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001306 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001307 log.error(":getAllFlowPaths failed");
1308 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001309 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001310 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001311 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001312 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001313
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001314 for (IFlowPath flowObj : flowPathsObj) {
1315 //
1316 // Extract the Flow state
1317 //
1318 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001319 if (flowPath != null)
1320 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001321 }
1322
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001323 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001324
1325 return flowPaths;
1326 }
admin944ef4f2013-10-08 17:48:37 -07001327
1328 /**
1329 * Get all Flows information, without the associated Flow Entries.
1330 *
1331 * @return all Flows information, without the associated Flow Entries.
1332 */
1333 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001334 Iterable<IFlowPath> flowPathsObj = null;
1335 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1336 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1337
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001338 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001339
Jonathan Hart01f2d272013-04-04 20:03:46 -07001340 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001341 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001342 log.debug("Get all FlowPaths: found FlowPaths");
1343 } else {
1344 log.debug("Get all FlowPaths: no FlowPaths found");
1345 }
1346 } catch (Exception e) {
1347 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001348 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001349 log.error(":getAllFlowPaths failed");
1350 }
1351 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1352 return new ArrayList<IFlowPath>(); // No Flows found
1353 }
1354
1355 for (IFlowPath flowObj : flowPathsObj){
1356 flowPathsObjArray.add(flowObj);
1357 }
1358 /*
1359 for (IFlowPath flowObj : flowPathsObj) {
1360 //
1361 // Extract the Flow state
1362 //
1363 FlowPath flowPath = extractFlowPath(flowObj);
1364 if (flowPath != null)
1365 flowPaths.add(flowPath);
1366 }
1367 */
1368
1369 //conn.endTx(Transaction.COMMIT);
1370
1371 return flowPathsObjArray;
1372 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001373
1374 /**
1375 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1376 *
1377 * @param flowObj the object to extract the Flow Path State from.
1378 * @return the extracted Flow Path State.
1379 */
1380 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001381 //
1382 // Extract the Flow state
1383 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001384 String flowIdStr = flowObj.getFlowId();
1385 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001386 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001387 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001388 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001389 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001390 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001391
1392 if ((flowIdStr == null) ||
1393 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001394 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001395 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001396 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001397 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001398 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001399 // TODO: A work-around, becauuse of some bogus database objects
1400 return null;
1401 }
1402
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001403 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001404 flowPath.setFlowId(new FlowId(flowIdStr));
1405 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001406 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001407 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001408 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001409 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001410 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001411 //
1412 // Extract the match conditions common for all Flow Entries
1413 //
1414 {
1415 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001416 String matchSrcMac = flowObj.getMatchSrcMac();
1417 if (matchSrcMac != null)
1418 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1419 String matchDstMac = flowObj.getMatchDstMac();
1420 if (matchDstMac != null)
1421 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001422 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1423 if (matchEthernetFrameType != null)
1424 match.enableEthernetFrameType(matchEthernetFrameType);
1425 Short matchVlanId = flowObj.getMatchVlanId();
1426 if (matchVlanId != null)
1427 match.enableVlanId(matchVlanId);
1428 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1429 if (matchVlanPriority != null)
1430 match.enableVlanPriority(matchVlanPriority);
1431 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1432 if (matchSrcIPv4Net != null)
1433 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1434 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1435 if (matchDstIPv4Net != null)
1436 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1437 Byte matchIpProto = flowObj.getMatchIpProto();
1438 if (matchIpProto != null)
1439 match.enableIpProto(matchIpProto);
1440 Byte matchIpToS = flowObj.getMatchIpToS();
1441 if (matchIpToS != null)
1442 match.enableIpToS(matchIpToS);
1443 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1444 if (matchSrcTcpUdpPort != null)
1445 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1446 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1447 if (matchDstTcpUdpPort != null)
1448 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1449
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001450 flowPath.setFlowEntryMatch(match);
1451 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001452 //
1453 // Extract the actions for the first Flow Entry
1454 //
1455 {
1456 String actionsStr = flowObj.getActions();
1457 if (actionsStr != null) {
1458 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1459 flowPath.setFlowEntryActions(flowEntryActions);
1460 }
1461 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001462
1463 //
1464 // Extract all Flow Entries
1465 //
1466 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1467 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001468 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1469 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001470 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001471 flowPath.dataPath().flowEntries().add(flowEntry);
1472 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001473
1474 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001475 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001476
1477 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001478 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1479 *
1480 * @param flowEntryObj the object to extract the Flow Entry State from.
1481 * @return the extracted Flow Entry State.
1482 */
1483 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1484 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1485 String switchDpidStr = flowEntryObj.getSwitchDpid();
1486 String userState = flowEntryObj.getUserState();
1487 String switchState = flowEntryObj.getSwitchState();
1488
1489 if ((flowEntryIdStr == null) ||
1490 (switchDpidStr == null) ||
1491 (userState == null) ||
1492 (switchState == null)) {
1493 // TODO: A work-around, becauuse of some bogus database objects
1494 return null;
1495 }
1496
1497 FlowEntry flowEntry = new FlowEntry();
1498 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1499 flowEntry.setDpid(new Dpid(switchDpidStr));
1500
1501 //
1502 // Extract the match conditions
1503 //
1504 FlowEntryMatch match = new FlowEntryMatch();
1505 Short matchInPort = flowEntryObj.getMatchInPort();
1506 if (matchInPort != null)
1507 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001508 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1509 if (matchSrcMac != null)
1510 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1511 String matchDstMac = flowEntryObj.getMatchDstMac();
1512 if (matchDstMac != null)
1513 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001514 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1515 if (matchEthernetFrameType != null)
1516 match.enableEthernetFrameType(matchEthernetFrameType);
1517 Short matchVlanId = flowEntryObj.getMatchVlanId();
1518 if (matchVlanId != null)
1519 match.enableVlanId(matchVlanId);
1520 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1521 if (matchVlanPriority != null)
1522 match.enableVlanPriority(matchVlanPriority);
1523 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1524 if (matchSrcIPv4Net != null)
1525 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1526 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1527 if (matchDstIPv4Net != null)
1528 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1529 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1530 if (matchIpProto != null)
1531 match.enableIpProto(matchIpProto);
1532 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1533 if (matchIpToS != null)
1534 match.enableIpToS(matchIpToS);
1535 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1536 if (matchSrcTcpUdpPort != null)
1537 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1538 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1539 if (matchDstTcpUdpPort != null)
1540 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001541 flowEntry.setFlowEntryMatch(match);
1542
1543 //
1544 // Extract the actions
1545 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001546 FlowEntryActions actions = new FlowEntryActions();
1547 String actionsStr = flowEntryObj.getActions();
1548 if (actionsStr != null)
1549 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001550 flowEntry.setFlowEntryActions(actions);
1551 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1552 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1553 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001554 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001555 //
1556 return flowEntry;
1557 }
1558
1559 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001560 * Add and maintain a shortest-path flow.
1561 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001562 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001563 *
1564 * @param flowPath the Flow Path with the endpoints and the match
1565 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001566 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001567 */
1568 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001569 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001570 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001571 // Don't do the shortest path computation here.
1572 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001573 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001574
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001575 // We need the DataPath to populate the Network MAP
1576 DataPath dataPath = new DataPath();
1577 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1578 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001579
1580 //
1581 // Prepare the computed Flow Path
1582 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001583 FlowPath computedFlowPath = new FlowPath();
1584 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1585 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001586 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001587 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001588 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001589 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001590
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001591 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001592 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001593 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001594 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001595
1596 // TODO: Mark the flow for maintenance purpose
1597
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001598 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001599 }
1600
1601 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001602 * Reconcile a flow.
1603 *
1604 * @param flowObj the flow that needs to be reconciliated.
1605 * @param newDataPath the new data path to use.
1606 * @return true on success, otherwise false.
1607 */
1608 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1609 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1610
1611 //
1612 // Set the incoming port matching and the outgoing port output
1613 // actions for each flow entry.
1614 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001615 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001616 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1617 // Set the incoming port matching
1618 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1619 flowEntry.setFlowEntryMatch(flowEntryMatch);
1620 flowEntryMatch.enableInPort(flowEntry.inPort());
1621
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001622 //
1623 // Set the actions
1624 //
1625 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1626 //
1627 // If the first Flow Entry, copy the Flow Path actions to it
1628 //
1629 if (idx == 0) {
1630 String actionsStr = flowObj.getActions();
1631 if (actionsStr != null) {
1632 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1633 for (FlowEntryAction action : flowActions.actions())
1634 flowEntryActions.addAction(action);
1635 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001636 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001637 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001638 //
1639 // Add the outgoing port output action
1640 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001641 FlowEntryAction flowEntryAction = new FlowEntryAction();
1642 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001643 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001644 }
1645
1646 //
1647 // Remove the old Flow Entries, and add the new Flow Entries
1648 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001649 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1650 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1651 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001652 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001653 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001654 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001655 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001656 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001657 }
1658
1659 //
1660 // Set the Data Path Summary
1661 //
1662 String dataPathSummaryStr = newDataPath.dataPathSummary();
1663 flowObj.setDataPathSummary(dataPathSummaryStr);
1664
1665 return true;
1666 }
1667
1668 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001669 * Reconcile all flows in a set.
1670 *
1671 * @param flowObjSet the set of flows that need to be reconciliated.
1672 */
1673 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1674 if (! flowObjSet.iterator().hasNext())
1675 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001676 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001677 }
1678
1679 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001680 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001681 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001682 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001683 * @param flowObj the flow path object for the flow entry to install.
1684 * @param flowEntryObj the flow entry object to install.
1685 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001686 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001687 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1688 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001689 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1690 if (flowEntryIdStr == null)
1691 return false;
1692 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001693 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001694 if (userState == null)
1695 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001696
1697 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001698 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001699 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001700 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1701 .getMessage(OFType.FLOW_MOD);
1702 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001703
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001704 short flowModCommand = OFFlowMod.OFPFC_ADD;
1705 if (userState.equals("FE_USER_ADD")) {
1706 flowModCommand = OFFlowMod.OFPFC_ADD;
1707 } else if (userState.equals("FE_USER_MODIFY")) {
1708 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1709 } else if (userState.equals("FE_USER_DELETE")) {
1710 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1711 } else {
1712 // Unknown user state. Ignore the entry
1713 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1714 flowEntryId.toString(), userState);
1715 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001716 }
1717
1718 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001719 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001720 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001721 // NOTE: The Flow matching conditions common for all Flow Entries are
1722 // used ONLY if a Flow Entry does NOT have the corresponding matching
1723 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001724 //
1725 OFMatch match = new OFMatch();
1726 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001727
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001728 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001729 Short matchInPort = flowEntryObj.getMatchInPort();
1730 if (matchInPort != null) {
1731 match.setInputPort(matchInPort);
1732 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1733 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001734
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001735 // Match the Source MAC address
1736 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1737 if (matchSrcMac == null)
1738 matchSrcMac = flowObj.getMatchSrcMac();
1739 if (matchSrcMac != null) {
1740 match.setDataLayerSource(matchSrcMac);
1741 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1742 }
1743
1744 // Match the Destination MAC address
1745 String matchDstMac = flowEntryObj.getMatchDstMac();
1746 if (matchDstMac == null)
1747 matchDstMac = flowObj.getMatchDstMac();
1748 if (matchDstMac != null) {
1749 match.setDataLayerDestination(matchDstMac);
1750 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1751 }
1752
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001753 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001754 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1755 if (matchEthernetFrameType == null)
1756 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1757 if (matchEthernetFrameType != null) {
1758 match.setDataLayerType(matchEthernetFrameType);
1759 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1760 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001761
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001762 // Match the VLAN ID
1763 Short matchVlanId = flowEntryObj.getMatchVlanId();
1764 if (matchVlanId == null)
1765 matchVlanId = flowObj.getMatchVlanId();
1766 if (matchVlanId != null) {
1767 match.setDataLayerVirtualLan(matchVlanId);
1768 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1769 }
1770
1771 // Match the VLAN priority
1772 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1773 if (matchVlanPriority == null)
1774 matchVlanPriority = flowObj.getMatchVlanPriority();
1775 if (matchVlanPriority != null) {
1776 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1777 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1778 }
1779
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001780 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001781 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1782 if (matchSrcIPv4Net == null)
1783 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1784 if (matchSrcIPv4Net != null) {
1785 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1786 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001787
1788 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001789 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1790 if (matchDstIPv4Net == null)
1791 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1792 if (matchDstIPv4Net != null) {
1793 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1794 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001795
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001796 // Match the IP protocol
1797 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1798 if (matchIpProto == null)
1799 matchIpProto = flowObj.getMatchIpProto();
1800 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001801 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001802 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001803 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001804
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001805 // Match the IP ToS (DSCP field, 6 bits)
1806 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1807 if (matchIpToS == null)
1808 matchIpToS = flowObj.getMatchIpToS();
1809 if (matchIpToS != null) {
1810 match.setNetworkTypeOfService(matchIpToS);
1811 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1812 }
1813
1814 // Match the Source TCP/UDP port
1815 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1816 if (matchSrcTcpUdpPort == null)
1817 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1818 if (matchSrcTcpUdpPort != null) {
1819 match.setTransportSource(matchSrcTcpUdpPort);
1820 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1821 }
1822
1823 // Match the Destination TCP/UDP port
1824 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1825 if (matchDstTcpUdpPort == null)
1826 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1827 if (matchDstTcpUdpPort != null) {
1828 match.setTransportDestination(matchDstTcpUdpPort);
1829 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001830 }
1831
1832 //
1833 // Fetch the actions
1834 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001835 Short actionOutputPort = null;
1836 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1837 int actionsLen = 0;
1838 FlowEntryActions flowEntryActions = null;
1839 String actionsStr = flowEntryObj.getActions();
1840 if (actionsStr != null)
1841 flowEntryActions = new FlowEntryActions(actionsStr);
1842 for (FlowEntryAction action : flowEntryActions.actions()) {
1843 ActionOutput actionOutput = action.actionOutput();
1844 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1845 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1846 ActionStripVlan actionStripVlan = action.actionStripVlan();
1847 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1848 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1849 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1850 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1851 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1852 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1853 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1854 ActionEnqueue actionEnqueue = action.actionEnqueue();
1855
1856 if (actionOutput != null) {
1857 actionOutputPort = actionOutput.port().value();
1858 // XXX: The max length is hard-coded for now
1859 OFActionOutput ofa =
1860 new OFActionOutput(actionOutput.port().value(),
1861 (short)0xffff);
1862 openFlowActions.add(ofa);
1863 actionsLen += ofa.getLength();
1864 }
1865
1866 if (actionSetVlanId != null) {
1867 OFActionVirtualLanIdentifier ofa =
1868 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1869 openFlowActions.add(ofa);
1870 actionsLen += ofa.getLength();
1871 }
1872
1873 if (actionSetVlanPriority != null) {
1874 OFActionVirtualLanPriorityCodePoint ofa =
1875 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1876 openFlowActions.add(ofa);
1877 actionsLen += ofa.getLength();
1878 }
1879
1880 if (actionStripVlan != null) {
1881 if (actionStripVlan.stripVlan() == true) {
1882 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1883 openFlowActions.add(ofa);
1884 actionsLen += ofa.getLength();
1885 }
1886 }
1887
1888 if (actionSetEthernetSrcAddr != null) {
1889 OFActionDataLayerSource ofa =
1890 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1891 openFlowActions.add(ofa);
1892 actionsLen += ofa.getLength();
1893 }
1894
1895 if (actionSetEthernetDstAddr != null) {
1896 OFActionDataLayerDestination ofa =
1897 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1898 openFlowActions.add(ofa);
1899 actionsLen += ofa.getLength();
1900 }
1901
1902 if (actionSetIPv4SrcAddr != null) {
1903 OFActionNetworkLayerSource ofa =
1904 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1905 openFlowActions.add(ofa);
1906 actionsLen += ofa.getLength();
1907 }
1908
1909 if (actionSetIPv4DstAddr != null) {
1910 OFActionNetworkLayerDestination ofa =
1911 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1912 openFlowActions.add(ofa);
1913 actionsLen += ofa.getLength();
1914 }
1915
1916 if (actionSetIpToS != null) {
1917 OFActionNetworkTypeOfService ofa =
1918 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1919 openFlowActions.add(ofa);
1920 actionsLen += ofa.getLength();
1921 }
1922
1923 if (actionSetTcpUdpSrcPort != null) {
1924 OFActionTransportLayerSource ofa =
1925 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1926 openFlowActions.add(ofa);
1927 actionsLen += ofa.getLength();
1928 }
1929
1930 if (actionSetTcpUdpDstPort != null) {
1931 OFActionTransportLayerDestination ofa =
1932 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1933 openFlowActions.add(ofa);
1934 actionsLen += ofa.getLength();
1935 }
1936
1937 if (actionEnqueue != null) {
1938 OFActionEnqueue ofa =
1939 new OFActionEnqueue(actionEnqueue.port().value(),
1940 actionEnqueue.queueId());
1941 openFlowActions.add(ofa);
1942 actionsLen += ofa.getLength();
1943 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001944 }
1945
1946 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1947 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1948 .setPriority(PRIORITY_DEFAULT)
1949 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1950 .setCookie(cookie)
1951 .setCommand(flowModCommand)
1952 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001953 .setActions(openFlowActions)
1954 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001955 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1956 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1957 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1958 if (actionOutputPort != null)
1959 fm.setOutPort(actionOutputPort);
1960 }
1961
1962 //
1963 // TODO: Set the following flag
1964 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1965 // See method ForwardingBase::pushRoute()
1966 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001967
1968 //
1969 // Write the message to the switch
1970 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001971 log.debug("MEASUREMENT: Installing flow entry " + userState +
1972 " into switch DPID: " +
1973 mySwitch.getStringId() +
1974 " flowEntryId: " + flowEntryId.toString() +
1975 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1976 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1977 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001978 try {
1979 messageDamper.write(mySwitch, fm, null);
1980 mySwitch.flush();
1981 //
1982 // TODO: We should use the OpenFlow Barrier mechanism
1983 // to check for errors, and update the SwitchState
1984 // for a flow entry after the Barrier message is
1985 // is received.
1986 //
1987 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1988 } catch (IOException e) {
1989 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001990 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001991 }
1992
1993 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001994 }
1995
1996 /**
1997 * Install a Flow Entry on a switch.
1998 *
1999 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002000 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002001 * @param flowEntry the flow entry to install.
2002 * @return true on success, otherwise false.
2003 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002004 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2005 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002006 //
2007 // Create the OpenFlow Flow Modification Entry to push
2008 //
2009 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
2010 .getMessage(OFType.FLOW_MOD);
2011 long cookie = flowEntry.flowEntryId().value();
2012
2013 short flowModCommand = OFFlowMod.OFPFC_ADD;
2014 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
2015 flowModCommand = OFFlowMod.OFPFC_ADD;
2016 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
2017 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
2018 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
2019 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
2020 } else {
2021 // Unknown user state. Ignore the entry
2022 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
2023 flowEntry.flowEntryId().toString(),
2024 flowEntry.flowEntryUserState());
2025 return false;
2026 }
2027
2028 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002029 // Fetch the match conditions.
2030 //
2031 // NOTE: The Flow matching conditions common for all Flow Entries are
2032 // used ONLY if a Flow Entry does NOT have the corresponding matching
2033 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002034 //
2035 OFMatch match = new OFMatch();
2036 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002037 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
2038 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
2039
2040 // Match the Incoming Port
2041 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002042 if (matchInPort != null) {
2043 match.setInputPort(matchInPort.value());
2044 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
2045 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002046
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002047 // Match the Source MAC address
2048 MACAddress matchSrcMac = flowEntryMatch.srcMac();
2049 if ((matchSrcMac == null) && (flowPathMatch != null)) {
2050 matchSrcMac = flowPathMatch.srcMac();
2051 }
2052 if (matchSrcMac != null) {
2053 match.setDataLayerSource(matchSrcMac.toString());
2054 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2055 }
2056
2057 // Match the Destination MAC address
2058 MACAddress matchDstMac = flowEntryMatch.dstMac();
2059 if ((matchDstMac == null) && (flowPathMatch != null)) {
2060 matchDstMac = flowPathMatch.dstMac();
2061 }
2062 if (matchDstMac != null) {
2063 match.setDataLayerDestination(matchDstMac.toString());
2064 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2065 }
2066
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002067 // Match the Ethernet Frame Type
2068 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2069 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2070 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2071 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002072 if (matchEthernetFrameType != null) {
2073 match.setDataLayerType(matchEthernetFrameType);
2074 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2075 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002076
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002077 // Match the VLAN ID
2078 Short matchVlanId = flowEntryMatch.vlanId();
2079 if ((matchVlanId == null) && (flowPathMatch != null)) {
2080 matchVlanId = flowPathMatch.vlanId();
2081 }
2082 if (matchVlanId != null) {
2083 match.setDataLayerVirtualLan(matchVlanId);
2084 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2085 }
2086
2087 // Match the VLAN priority
2088 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2089 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2090 matchVlanPriority = flowPathMatch.vlanPriority();
2091 }
2092 if (matchVlanPriority != null) {
2093 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2094 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2095 }
2096
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002097 // Match the Source IPv4 Network prefix
2098 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2099 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2100 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2101 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002102 if (matchSrcIPv4Net != null) {
2103 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2104 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002105
2106 // Natch the Destination IPv4 Network prefix
2107 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2108 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2109 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2110 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002111 if (matchDstIPv4Net != null) {
2112 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2113 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002114
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002115 // Match the IP protocol
2116 Byte matchIpProto = flowEntryMatch.ipProto();
2117 if ((matchIpProto == null) && (flowPathMatch != null)) {
2118 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002119 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002120 if (matchIpProto != null) {
2121 match.setNetworkProtocol(matchIpProto);
2122 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002123 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002124
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002125 // Match the IP ToS (DSCP field, 6 bits)
2126 Byte matchIpToS = flowEntryMatch.ipToS();
2127 if ((matchIpToS == null) && (flowPathMatch != null)) {
2128 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002129 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002130 if (matchIpToS != null) {
2131 match.setNetworkTypeOfService(matchIpToS);
2132 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2133 }
2134
2135 // Match the Source TCP/UDP port
2136 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2137 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2138 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2139 }
2140 if (matchSrcTcpUdpPort != null) {
2141 match.setTransportSource(matchSrcTcpUdpPort);
2142 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2143 }
2144
2145 // Match the Destination TCP/UDP port
2146 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2147 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2148 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2149 }
2150 if (matchDstTcpUdpPort != null) {
2151 match.setTransportDestination(matchDstTcpUdpPort);
2152 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002153 }
2154
2155 //
2156 // Fetch the actions
2157 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002158 Short actionOutputPort = null;
2159 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2160 int actionsLen = 0;
2161 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002162 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002163 for (FlowEntryAction action : flowEntryActions.actions()) {
2164 ActionOutput actionOutput = action.actionOutput();
2165 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2166 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2167 ActionStripVlan actionStripVlan = action.actionStripVlan();
2168 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2169 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2170 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2171 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2172 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2173 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2174 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2175 ActionEnqueue actionEnqueue = action.actionEnqueue();
2176
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002177 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002178 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002179 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002180 OFActionOutput ofa =
2181 new OFActionOutput(actionOutput.port().value(),
2182 (short)0xffff);
2183 openFlowActions.add(ofa);
2184 actionsLen += ofa.getLength();
2185 }
2186
2187 if (actionSetVlanId != null) {
2188 OFActionVirtualLanIdentifier ofa =
2189 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2190 openFlowActions.add(ofa);
2191 actionsLen += ofa.getLength();
2192 }
2193
2194 if (actionSetVlanPriority != null) {
2195 OFActionVirtualLanPriorityCodePoint ofa =
2196 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2197 openFlowActions.add(ofa);
2198 actionsLen += ofa.getLength();
2199 }
2200
2201 if (actionStripVlan != null) {
2202 if (actionStripVlan.stripVlan() == true) {
2203 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2204 openFlowActions.add(ofa);
2205 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002206 }
2207 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002208
2209 if (actionSetEthernetSrcAddr != null) {
2210 OFActionDataLayerSource ofa =
2211 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2212 openFlowActions.add(ofa);
2213 actionsLen += ofa.getLength();
2214 }
2215
2216 if (actionSetEthernetDstAddr != null) {
2217 OFActionDataLayerDestination ofa =
2218 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2219 openFlowActions.add(ofa);
2220 actionsLen += ofa.getLength();
2221 }
2222
2223 if (actionSetIPv4SrcAddr != null) {
2224 OFActionNetworkLayerSource ofa =
2225 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2226 openFlowActions.add(ofa);
2227 actionsLen += ofa.getLength();
2228 }
2229
2230 if (actionSetIPv4DstAddr != null) {
2231 OFActionNetworkLayerDestination ofa =
2232 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2233 openFlowActions.add(ofa);
2234 actionsLen += ofa.getLength();
2235 }
2236
2237 if (actionSetIpToS != null) {
2238 OFActionNetworkTypeOfService ofa =
2239 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2240 openFlowActions.add(ofa);
2241 actionsLen += ofa.getLength();
2242 }
2243
2244 if (actionSetTcpUdpSrcPort != null) {
2245 OFActionTransportLayerSource ofa =
2246 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2247 openFlowActions.add(ofa);
2248 actionsLen += ofa.getLength();
2249 }
2250
2251 if (actionSetTcpUdpDstPort != null) {
2252 OFActionTransportLayerDestination ofa =
2253 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2254 openFlowActions.add(ofa);
2255 actionsLen += ofa.getLength();
2256 }
2257
2258 if (actionEnqueue != null) {
2259 OFActionEnqueue ofa =
2260 new OFActionEnqueue(actionEnqueue.port().value(),
2261 actionEnqueue.queueId());
2262 openFlowActions.add(ofa);
2263 actionsLen += ofa.getLength();
2264 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002265 }
2266
2267 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2268 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2269 .setPriority(PRIORITY_DEFAULT)
2270 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2271 .setCookie(cookie)
2272 .setCommand(flowModCommand)
2273 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002274 .setActions(openFlowActions)
2275 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2276 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2277 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2278 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2279 if (actionOutputPort != null)
2280 fm.setOutPort(actionOutputPort);
2281 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002282
2283 //
2284 // TODO: Set the following flag
2285 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2286 // See method ForwardingBase::pushRoute()
2287 //
2288
2289 //
2290 // Write the message to the switch
2291 //
2292 try {
2293 messageDamper.write(mySwitch, fm, null);
2294 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002295 //
2296 // TODO: We should use the OpenFlow Barrier mechanism
2297 // to check for errors, and update the SwitchState
2298 // for a flow entry after the Barrier message is
2299 // is received.
2300 //
2301 // TODO: The FlowEntry Object in Titan should be set
2302 // to FE_SWITCH_UPDATED.
2303 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002304 } catch (IOException e) {
2305 log.error("Failure writing flow mod from network map", e);
2306 return false;
2307 }
2308 return true;
2309 }
2310
2311 /**
2312 * Remove a Flow Entry from a switch.
2313 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002314 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002315 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002316 * @param flowEntry the flow entry to remove.
2317 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002318 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002319 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2320 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002321 //
2322 // The installFlowEntry() method implements both installation
2323 // and removal of flow entries.
2324 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002325 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002326 }
2327
2328 /**
2329 * Install a Flow Entry on a remote controller.
2330 *
2331 * TODO: We need it now: Jono
2332 * - For now it will make a REST call to the remote controller.
2333 * - Internally, it needs to know the name of the remote controller.
2334 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002335 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002336 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002337 * @return true on success, otherwise false.
2338 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002339 public boolean installRemoteFlowEntry(FlowPath flowPath,
2340 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002341 // TODO: We need it now: Jono
2342 // - For now it will make a REST call to the remote controller.
2343 // - Internally, it needs to know the name of the remote controller.
2344 return true;
2345 }
2346
2347 /**
2348 * Remove a flow entry on a remote controller.
2349 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002350 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002351 * @param flowEntry the flow entry to remove.
2352 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002353 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002354 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2355 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002356 //
2357 // The installRemoteFlowEntry() method implements both installation
2358 // and removal of flow entries.
2359 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002360 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002361 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002362}