blob: 0888a808a26e3533f3945c4667da2fbf919038fe [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07006import java.util.Collections;
7import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -070010import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000011import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080012import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080013import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000014import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070015import java.util.TreeMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
17import java.util.concurrent.ScheduledExecutorService;
18import java.util.concurrent.ScheduledFuture;
19import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
22import net.floodlightcontroller.core.INetMapStorage;
23import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
24import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070025import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070026import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070027import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080028import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080029import net.floodlightcontroller.core.module.FloodlightModuleContext;
30import net.floodlightcontroller.core.module.FloodlightModuleException;
31import net.floodlightcontroller.core.module.IFloodlightModule;
32import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080033import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
34import net.floodlightcontroller.restserver.IRestApiService;
35import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080036import net.floodlightcontroller.util.DataPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080037import net.floodlightcontroller.util.DataPathEndpoints;
Jonathan Hart01f2d272013-04-04 20:03:46 -070038import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070040import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080041import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070042import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.FlowEntrySwitchState;
44import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080045import net.floodlightcontroller.util.FlowId;
46import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070047import net.floodlightcontroller.util.IPv4Net;
48import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080049import net.floodlightcontroller.util.OFMessageDamper;
50import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070051import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.onrc.onos.util.GraphDBConnection;
53import net.onrc.onos.util.GraphDBConnection.Transaction;
54
55import org.openflow.protocol.OFFlowMod;
56import org.openflow.protocol.OFMatch;
57import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070058import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080059import org.openflow.protocol.OFType;
60import org.openflow.protocol.action.OFAction;
61import org.openflow.protocol.action.OFActionOutput;
Jonathan Hartf5315fb2013-04-05 11:41:56 -070062import org.openflow.util.HexString;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063import org.slf4j.Logger;
64import org.slf4j.LoggerFactory;
65
Jonathan Hartf5315fb2013-04-05 11:41:56 -070066
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070067public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080068
69 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080070
71 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080072 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070073 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070074 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080075
76 protected OFMessageDamper messageDamper;
77
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070078 //
79 // TODO: Values copied from elsewhere (class LearningSwitch).
80 // The local copy should go away!
81 //
82 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
83 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
84 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
85 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
86 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080087
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000088 // Flow Entry ID generation state
89 private static Random randomGenerator = new Random();
90 private static int nextFlowEntryIdPrefix = 0;
91 private static int nextFlowEntryIdSuffix = 0;
92 private static long nextFlowEntryId = 0;
93
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070094 private static long measurementFlowId = 100000;
95 private static String measurementFlowIdStr = "0x186a0"; // 100000
96 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070097
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080098 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080099 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
100
101 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700102 private final ScheduledExecutorService mapReaderScheduler =
103 Executors.newScheduledThreadPool(1);
104
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700105 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800106 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700107 long startTime = System.nanoTime();
108 int counterAllFlowEntries = 0;
109 int counterMyNotUpdatedFlowEntries = 0;
110 int counterAllFlowPaths = 0;
111 int counterMyFlowPaths = 0;
112
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800113 if (floodlightProvider == null) {
114 log.debug("FloodlightProvider service not found!");
115 return;
116 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000117 Map<Long, IOFSwitch> mySwitches =
118 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700119 LinkedList<IFlowEntry> addFlowEntries =
120 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000121 LinkedList<IFlowEntry> deleteFlowEntries =
122 new LinkedList<IFlowEntry>();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000123 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700124
125 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700126 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700127 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700129 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 Iterable<IFlowEntry> allFlowEntries =
131 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700132 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700133 counterAllFlowEntries++;
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700134 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000135 if ((switchState == null) ||
136 (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137 continue; // Ignore the entry: nothing to do
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000138 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000140 String dpidStr = flowEntryObj.getSwitchDpid();
141 if (dpidStr == null)
142 continue;
143 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800144 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000145 if (mySwitch == null)
146 continue; // Ignore the entry: not my switch
147
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700148 IFlowPath flowObj =
149 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
150 if (flowObj == null)
151 continue; // Should NOT happen
152 if (flowObj.getFlowId() == null)
153 continue; // Invalid entry
154
155 //
156 // NOTE: For now we process the DELETE before the ADD
157 // to cover the more common scenario.
158 // TODO: This is error prone and needs to be fixed!
159 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000160 String userState = flowEntryObj.getUserState();
161 if (userState == null)
162 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700163 if (userState.equals("FE_USER_DELETE")) {
164 // An entry that needs to be deleted.
165 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 installFlowEntry(mySwitch, flowObj, flowEntryObj);
167 } else {
168 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700169 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700170 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700171 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700172 // TODO: Commented-out for now
173 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700175 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700176 processed_measurement_flow = true;
177 }
178 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700179 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700180 }
181
182 /*
183 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
184 addFlowEntries.size() + deleteFlowEntries.size());
185 */
186
187 //
188 // Process the Flow Entries that need to be added
189 //
190 for (IFlowEntry flowEntryObj : addFlowEntries) {
191 IFlowPath flowObj =
192 conn.utils().getFlowPathByFlowEntry(conn,
193 flowEntryObj);
194 if (flowObj == null)
195 continue; // Should NOT happen
196 if (flowObj.getFlowId() == null)
197 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000201 if (mySwitch == null)
202 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700203 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800204 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000205
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700206 /*
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700207 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
208 deleteFlowEntries.size());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700209 */
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700210
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000212 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700213 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000214 //
215 // TODO: We should use the OpenFlow Barrier mechanism
216 // to check for errors, and delete the Flow Entries after the
217 // Barrier message is received.
218 //
219 while (! deleteFlowEntries.isEmpty()) {
220 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
221 IFlowPath flowObj =
222 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
223 if (flowObj == null) {
224 log.debug("Did not find FlowPath to be deleted");
225 continue;
226 }
227 flowObj.removeFlowEntry(flowEntryObj);
228 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000229 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700230
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700231 //
232 // Fetch and recompute the Shortest Path for those
233 // Flow Paths this controller is responsible for.
234 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700235 topoRouteService.prepareShortestPathTopo();
236 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700237 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700238 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700239 if (flowPathObj == null)
240 continue;
241 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
242 if (dataPathSummaryStr == null)
243 continue; // Could be invalid entry?
244 if (dataPathSummaryStr.isEmpty())
245 continue; // No need to maintain this flow
246
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700247 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000248 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700249 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700250 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700251 //
252 // Use the source DPID as a heuristic to decide
253 // which controller is responsible for maintaining the
254 // shortest path.
255 // NOTE: This heuristic is error-prone: if the switch
256 // goes away and no controller is responsible for that
257 // switch, then the original Flow Path is not cleaned-up
258 //
259 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
260 if (mySwitch == null)
261 continue; // Ignore: not my responsibility
262
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000263 //
264 // Test whether we need to complete the Flow cleanup,
265 // if the Flow has been deleted by the user.
266 //
267 String flowUserState = flowPathObj.getUserState();
268 if ((flowUserState != null)
269 && flowUserState.equals("FE_USER_DELETE")) {
270 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
271 boolean empty = true; // TODO: an ugly hack
272 for (IFlowEntry flowEntryObj : flowEntries) {
273 empty = false;
274 break;
275 }
276 if (empty)
277 deleteFlows.add(flowPathObj);
278 }
279
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000280 // Fetch the fields needed to recompute the shortest path
281 Short srcPortShort = flowPathObj.getSrcPort();
282 String dstDpidStr = flowPathObj.getDstSwitch();
283 Short dstPortShort = flowPathObj.getDstPort();
284 if ((srcPortShort == null) ||
285 (dstDpidStr == null) ||
286 (dstPortShort == null)) {
287 continue;
288 }
289
290 Port srcPort = new Port(srcPortShort);
291 Dpid dstDpid = new Dpid(dstDpidStr);
292 Port dstPort = new Port(dstPortShort);
293 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
294 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
295
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700296 counterMyFlowPaths++;
297
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700298 //
299 // NOTE: Using here the regular getShortestPath() method
300 // won't work here, because that method calls internally
301 // "conn.endTx(Transaction.COMMIT)", and that will
302 // invalidate all handlers to the Titan database.
303 // If we want to experiment with calling here
304 // getShortestPath(), we need to refactor that code
305 // to avoid closing the transaction.
306 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307 DataPath dataPath =
308 topoRouteService.getTopoShortestPath(srcSwitchPort,
309 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000310 if (dataPath == null) {
311 // We need the DataPath to compare the paths
312 dataPath = new DataPath();
313 dataPath.setSrcPort(srcSwitchPort);
314 dataPath.setDstPort(dstSwitchPort);
315 }
316
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700317 String newDataPathSummaryStr = dataPath.dataPathSummary();
318 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
319 continue; // Nothing changed
320
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700321 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700322 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000323
324 //
325 // Delete all leftover Flows marked for deletion from the
326 // Network MAP.
327 //
328 while (! deleteFlows.isEmpty()) {
329 IFlowPath flowPathObj = deleteFlows.poll();
330 conn.utils().removeFlowPath(conn, flowPathObj);
331 }
332
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700333 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700334
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800335 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700336
337 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700338 long estimatedTime =
339 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700340 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
341 (double)estimatedTime / 1000000000 + " sec";
342 log.debug(logMsg);
343 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700344
345 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700346 double rate = 0.0;
347 if (estimatedTime > 0)
348 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
349 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
350 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
351 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
352 counterAllFlowPaths + " MyFlowPaths: " +
353 counterMyFlowPaths + " in " +
354 (double)estimatedTime / 1000000000 + " sec: " +
355 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700356 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800357 }
358 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700359
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700360 final ScheduledFuture<?> mapReaderHandle =
361 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800362
363 @Override
364 public void init(String conf) {
365 conn = GraphDBConnection.getInstance(conf);
366 }
367
368 public void finalize() {
369 close();
370 }
371
372 @Override
373 public void close() {
374 conn.close();
375 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800376
377 @Override
378 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
379 Collection<Class<? extends IFloodlightService>> l =
380 new ArrayList<Class<? extends IFloodlightService>>();
381 l.add(IFlowService.class);
382 return l;
383 }
384
385 @Override
386 public Map<Class<? extends IFloodlightService>, IFloodlightService>
387 getServiceImpls() {
388 Map<Class<? extends IFloodlightService>,
389 IFloodlightService> m =
390 new HashMap<Class<? extends IFloodlightService>,
391 IFloodlightService>();
392 m.put(IFlowService.class, this);
393 return m;
394 }
395
396 @Override
397 public Collection<Class<? extends IFloodlightService>>
398 getModuleDependencies() {
399 Collection<Class<? extends IFloodlightService>> l =
400 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800401 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700402 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800403 l.add(IRestApiService.class);
404 return l;
405 }
406
407 @Override
408 public void init(FloodlightModuleContext context)
409 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700410 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800411 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700412 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800413 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
415 EnumSet.of(OFType.FLOW_MOD),
416 OFMESSAGE_DAMPER_TIMEOUT);
417 // TODO: An ugly hack!
418 String conf = "/tmp/cassandra.titan";
419 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800420 }
421
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000422 private long getNextFlowEntryId() {
423 //
424 // Generate the next Flow Entry ID.
425 // NOTE: For now, the higher 32 bits are random, and
426 // the lower 32 bits are sequential.
427 // In the future, we need a better allocation mechanism.
428 //
429 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
430 nextFlowEntryIdPrefix = randomGenerator.nextInt();
431 nextFlowEntryIdSuffix = 0;
432 } else {
433 nextFlowEntryIdSuffix++;
434 }
435 long result = (long)nextFlowEntryIdPrefix << 32;
436 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
437 return result;
438 }
439
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800440 @Override
441 public void startUp(FloodlightModuleContext context) {
442 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700443
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000444 // Initialize the Flow Entry ID generator
445 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800446 }
447
448 /**
449 * Add a flow.
450 *
451 * Internally, ONOS will automatically register the installer for
452 * receiving Flow Path Notifications for that path.
453 *
454 * @param flowPath the Flow Path to install.
455 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700456 * @param dataPathSummaryStr the data path summary string if the added
457 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800458 * @return true on success, otherwise false.
459 */
460 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700461 public boolean addFlow(FlowPath flowPath, FlowId flowId,
462 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700463 /*
464 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700465 if (flowPath.flowId().value() == measurementFlowId) {
466 modifiedMeasurementFlowTime = System.nanoTime();
467 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700468 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800469
470 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000471 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800472 try {
473 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
474 != null) {
475 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
476 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000477 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800478 } else {
479 flowObj = conn.utils().newFlowPath(conn);
480 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
481 flowPath.flowId().toString());
482 }
483 } catch (Exception e) {
484 // TODO: handle exceptions
485 conn.endTx(Transaction.ROLLBACK);
486 log.error(":addFlow FlowId:{} failed",
487 flowPath.flowId().toString());
488 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700489 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000490 log.error(":addFlow FlowId:{} failed: Flow object not created",
491 flowPath.flowId().toString());
492 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800493 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700494 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800495
496 //
497 // Set the Flow key:
498 // - flowId
499 //
500 flowObj.setFlowId(flowPath.flowId().toString());
501 flowObj.setType("flow");
502
503 //
504 // Set the Flow attributes:
505 // - flowPath.installerId()
506 // - flowPath.dataPath().srcPort()
507 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700508 // - flowPath.matchEthernetFrameType()
509 // - flowPath.matchSrcIPv4Net()
510 // - flowPath.matchDstIPv4Net()
511 // - flowPath.matchSrcMac()
512 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800513 //
514 flowObj.setInstallerId(flowPath.installerId().toString());
515 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
516 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
517 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
518 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700519 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
520 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
521 }
522 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
523 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
524 }
525 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
526 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
527 }
528 if (flowPath.flowEntryMatch().matchSrcMac()) {
529 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
530 }
531 if (flowPath.flowEntryMatch().matchDstMac()) {
532 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
533 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800534
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700535 if (dataPathSummaryStr != null) {
536 flowObj.setDataPathSummary(dataPathSummaryStr);
537 } else {
538 flowObj.setDataPathSummary("");
539 }
540
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000541 if (found)
542 flowObj.setUserState("FE_USER_MODIFY");
543 else
544 flowObj.setUserState("FE_USER_ADD");
545
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800546 // Flow edges:
547 // HeadFE
548
549
550 //
551 // Flow Entries:
552 // flowPath.dataPath().flowEntries()
553 //
554 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700555 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000556 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800557 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700558 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800559 }
560 conn.endTx(Transaction.COMMIT);
561
562 //
563 // TODO: We need a proper Flow ID allocation mechanism.
564 //
565 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700566
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800567 return true;
568 }
569
570 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700571 * Add a flow entry to the Network MAP.
572 *
573 * @param flowObj the corresponding Flow Path object for the Flow Entry.
574 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700575 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700576 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700577 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700578 // Flow edges
579 // HeadFE (TODO)
580
581 //
582 // Assign the FlowEntry ID.
583 //
584 if ((flowEntry.flowEntryId() == null) ||
585 (flowEntry.flowEntryId().value() == 0)) {
586 long id = getNextFlowEntryId();
587 flowEntry.setFlowEntryId(new FlowEntryId(id));
588 }
589
590 IFlowEntry flowEntryObj = null;
591 boolean found = false;
592 try {
593 if ((flowEntryObj =
594 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
595 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
596 flowEntry.flowEntryId().toString());
597 found = true;
598 } else {
599 flowEntryObj = conn.utils().newFlowEntry(conn);
600 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
601 flowEntry.flowEntryId().toString());
602 }
603 } catch (Exception e) {
604 log.error(":addFlow FlowEntryId:{} failed",
605 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700606 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700607 }
608 if (flowEntryObj == null) {
609 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
610 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700611 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700612 }
613
614 //
615 // Set the Flow Entry key:
616 // - flowEntry.flowEntryId()
617 //
618 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
619 flowEntryObj.setType("flow_entry");
620
621 //
622 // Set the Flow Entry Edges and attributes:
623 // - Switch edge
624 // - InPort edge
625 // - OutPort edge
626 //
627 // - flowEntry.flowEntryMatch()
628 // - flowEntry.flowEntryActions()
629 // - flowEntry.dpid()
630 // - flowEntry.flowEntryUserState()
631 // - flowEntry.flowEntrySwitchState()
632 // - flowEntry.flowEntryErrorState()
633 // - flowEntry.matchInPort()
634 // - flowEntry.matchEthernetFrameType()
635 // - flowEntry.matchSrcIPv4Net()
636 // - flowEntry.matchDstIPv4Net()
637 // - flowEntry.matchSrcMac()
638 // - flowEntry.matchDstMac()
639 // - flowEntry.actionOutput()
640 //
641 ISwitchObject sw =
642 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
643 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
644 flowEntryObj.setSwitch(sw);
645 if (flowEntry.flowEntryMatch().matchInPort()) {
646 IPortObject inport =
647 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
648 flowEntry.flowEntryMatch().inPort().value());
649 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
650 flowEntryObj.setInPort(inport);
651 }
652 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
653 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
654 }
655 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
656 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
657 }
658 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
659 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
660 }
661 if (flowEntry.flowEntryMatch().matchSrcMac()) {
662 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
663 }
664 if (flowEntry.flowEntryMatch().matchDstMac()) {
665 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
666 }
667
668 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
669 if (fa.actionOutput() != null) {
670 IPortObject outport =
671 conn.utils().searchPort(conn,
672 flowEntry.dpid().toString(),
673 fa.actionOutput().port().value());
674 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
675 flowEntryObj.setOutPort(outport);
676 }
677 }
678 // TODO: Hacks with hard-coded state names!
679 if (found)
680 flowEntryObj.setUserState("FE_USER_MODIFY");
681 else
682 flowEntryObj.setUserState("FE_USER_ADD");
683 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
684 //
685 // TODO: Take care of the FlowEntryErrorState.
686 //
687
688 // Flow Entries edges:
689 // Flow
690 // NextFE (TODO)
691 if (! found) {
692 flowObj.addFlowEntry(flowEntryObj);
693 flowEntryObj.setFlow(flowObj);
694 }
695
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700696 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700697 }
698
699 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800700 * Delete a previously added flow.
701 *
702 * @param flowId the Flow ID of the flow to delete.
703 * @return true on success, otherwise false.
704 */
705 @Override
706 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700707 /*
708 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700709 if (flowId.value() == measurementFlowId) {
710 modifiedMeasurementFlowTime = System.nanoTime();
711 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700712 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700713
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800714 IFlowPath flowObj = null;
715 //
716 // We just mark the entries for deletion,
717 // and let the switches remove each individual entry after
718 // it has been removed from the switches.
719 //
720 try {
721 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
722 != null) {
723 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
724 flowId.toString());
725 } else {
726 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
727 flowId.toString());
728 }
729 } catch (Exception e) {
730 // TODO: handle exceptions
731 conn.endTx(Transaction.ROLLBACK);
732 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
733 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700734 if (flowObj == null) {
735 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800736 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700737 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800738
739 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000740 // Find and mark for deletion all Flow Entries,
741 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800742 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000743 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800744 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
745 boolean empty = true; // TODO: an ugly hack
746 for (IFlowEntry flowEntryObj : flowEntries) {
747 empty = false;
748 // flowObj.removeFlowEntry(flowEntryObj);
749 // conn.utils().removeFlowEntry(conn, flowEntryObj);
750 flowEntryObj.setUserState("FE_USER_DELETE");
751 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
752 }
753 // Remove from the database empty flows
754 if (empty)
755 conn.utils().removeFlowPath(conn, flowObj);
756 conn.endTx(Transaction.COMMIT);
757
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800758 return true;
759 }
760
761 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700762 * Clear the state for a previously added flow.
763 *
764 * @param flowId the Flow ID of the flow to clear.
765 * @return true on success, otherwise false.
766 */
767 @Override
768 public boolean clearFlow(FlowId flowId) {
769 IFlowPath flowObj = null;
770 try {
771 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
772 != null) {
773 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
774 flowId.toString());
775 } else {
776 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
777 flowId.toString());
778 }
779 } catch (Exception e) {
780 // TODO: handle exceptions
781 conn.endTx(Transaction.ROLLBACK);
782 log.error(":clearFlow FlowId:{} failed", flowId.toString());
783 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700784 if (flowObj == null) {
785 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700786 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700787 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700788
789 //
790 // Remove all Flow Entries
791 //
792 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
793 for (IFlowEntry flowEntryObj : flowEntries) {
794 flowObj.removeFlowEntry(flowEntryObj);
795 conn.utils().removeFlowEntry(conn, flowEntryObj);
796 }
797 // Remove the Flow itself
798 conn.utils().removeFlowPath(conn, flowObj);
799 conn.endTx(Transaction.COMMIT);
800
801 return true;
802 }
803
804 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800805 * Get a previously added flow.
806 *
807 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800808 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800809 */
810 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800811 public FlowPath getFlow(FlowId flowId) {
812 IFlowPath flowObj = null;
813 try {
814 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
815 != null) {
816 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
817 flowId.toString());
818 } else {
819 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
820 flowId.toString());
821 }
822 } catch (Exception e) {
823 // TODO: handle exceptions
824 conn.endTx(Transaction.ROLLBACK);
825 log.error(":getFlow FlowId:{} failed", flowId.toString());
826 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700827 if (flowObj == null) {
828 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800829 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700830 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800831
832 //
833 // Extract the Flow state
834 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800835 FlowPath flowPath = extractFlowPath(flowObj);
836 conn.endTx(Transaction.COMMIT);
837
838 return flowPath;
839 }
840
841 /**
842 * Get all previously added flows by a specific installer for a given
843 * data path endpoints.
844 *
845 * @param installerId the Caller ID of the installer of the flow to get.
846 * @param dataPathEndpoints the data path endpoints of the flow to get.
847 * @return the Flow Paths if found, otherwise null.
848 */
849 @Override
850 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
851 DataPathEndpoints dataPathEndpoints) {
852 //
853 // TODO: The implementation below is not optimal:
854 // We fetch all flows, and then return only the subset that match
855 // the query conditions.
856 // We should use the appropriate Titan/Gremlin query to filter-out
857 // the flows as appropriate.
858 //
859 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700860 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800861
862 if (allFlows == null) {
863 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700864 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800865 }
866
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800867 for (FlowPath flow : allFlows) {
868 //
869 // TODO: String-based comparison is sub-optimal.
870 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800871 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800872 //
873 if (! flow.installerId().toString().equals(installerId.toString()))
874 continue;
875 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
876 continue;
877 }
878 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
879 continue;
880 }
881 flowPaths.add(flow);
882 }
883
884 if (flowPaths.isEmpty()) {
885 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800886 } else {
887 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
888 }
889
890 return flowPaths;
891 }
892
893 /**
894 * Get all installed flows by all installers for given data path endpoints.
895 *
896 * @param dataPathEndpoints the data path endpoints of the flows to get.
897 * @return the Flow Paths if found, otherwise null.
898 */
899 @Override
900 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
901 //
902 // TODO: The implementation below is not optimal:
903 // We fetch all flows, and then return only the subset that match
904 // the query conditions.
905 // We should use the appropriate Titan/Gremlin query to filter-out
906 // the flows as appropriate.
907 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700908 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
909 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800910
911 if (allFlows == null) {
912 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700913 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800914 }
915
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800916 for (FlowPath flow : allFlows) {
917 //
918 // TODO: String-based comparison is sub-optimal.
919 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800920 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800921 //
922 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
923 continue;
924 }
925 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
926 continue;
927 }
928 flowPaths.add(flow);
929 }
930
931 if (flowPaths.isEmpty()) {
932 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800933 } else {
934 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
935 }
936
937 return flowPaths;
938 }
939
940 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700941 * Get summary of all installed flows by all installers in a given range
942 *
943 * @param flowId the data path endpoints of the flows to get.
944 * @param maxFlows: the maximum number of flows to be returned
945 * @return the Flow Paths if found, otherwise null.
946 */
947 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700948 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700949
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700950 // TODO: The implementation below is not optimal:
951 // We fetch all flows, and then return only the subset that match
952 // the query conditions.
953 // We should use the appropriate Titan/Gremlin query to filter-out
954 // the flows as appropriate.
955 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700956 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700957
Jonathan Hart01f2d272013-04-04 20:03:46 -0700958 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
959
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700960 Collections.sort(flowPathsWithoutFlowEntries,
961 new Comparator<IFlowPath>(){
962 @Override
963 public int compare(IFlowPath first, IFlowPath second) {
964 // TODO Auto-generated method stub
965 long result = new FlowId(first.getFlowId()).value()
966 - new FlowId(second.getFlowId()).value();
967 if (result > 0) return 1;
968 else if (result < 0) return -1;
969 else return 0;
970 }
971 }
972 );
973
Jonathan Hart01f2d272013-04-04 20:03:46 -0700974 return flowPathsWithoutFlowEntries;
975
976 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700977 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -0700978
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700979 if (allFlows == null) {
980 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700981 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700982 }
983
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700984 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700985
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700986 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700987 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700988
Pavlin Radoslavov96b43422013-04-04 19:14:56 -0700989 // start from desired flowId
990 if (flow.flowId().value() < flowId.value()) {
991 continue;
992 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700993
994 // Summarize by making null flow entry fields that are not relevant to report
995 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
996 flowEntry.setFlowEntryActions(null);
997 flowEntry.setFlowEntryMatch(null);
998 }
999
1000 flowPaths.add(flow);
1001 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1002 break;
1003 }
1004 }
1005
1006 if (flowPaths.isEmpty()) {
1007 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001008 } else {
1009 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1010 }
1011
1012 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001013 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001014 }
1015
1016 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001017 * Get all installed flows by all installers.
1018 *
1019 * @return the Flow Paths if found, otherwise null.
1020 */
1021 @Override
1022 public ArrayList<FlowPath> getAllFlows() {
1023 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001024 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001025
1026 try {
1027 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1028 log.debug("Get all FlowPaths: found FlowPaths");
1029 } else {
1030 log.debug("Get all FlowPaths: no FlowPaths found");
1031 }
1032 } catch (Exception e) {
1033 // TODO: handle exceptions
1034 conn.endTx(Transaction.ROLLBACK);
1035 log.error(":getAllFlowPaths failed");
1036 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001037 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1038 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001039 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001040 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001041
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001042 for (IFlowPath flowObj : flowPathsObj) {
1043 //
1044 // Extract the Flow state
1045 //
1046 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001047 if (flowPath != null)
1048 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001049 }
1050
1051 conn.endTx(Transaction.COMMIT);
1052
1053 return flowPaths;
1054 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001055
1056 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1057 Iterable<IFlowPath> flowPathsObj = null;
1058 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1059 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1060
1061 try {
1062 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1063 log.debug("Get all FlowPaths: found FlowPaths");
1064 } else {
1065 log.debug("Get all FlowPaths: no FlowPaths found");
1066 }
1067 } catch (Exception e) {
1068 // TODO: handle exceptions
1069 conn.endTx(Transaction.ROLLBACK);
1070 log.error(":getAllFlowPaths failed");
1071 }
1072 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1073 return new ArrayList<IFlowPath>(); // No Flows found
1074 }
1075
1076 for (IFlowPath flowObj : flowPathsObj){
1077 flowPathsObjArray.add(flowObj);
1078 }
1079 /*
1080 for (IFlowPath flowObj : flowPathsObj) {
1081 //
1082 // Extract the Flow state
1083 //
1084 FlowPath flowPath = extractFlowPath(flowObj);
1085 if (flowPath != null)
1086 flowPaths.add(flowPath);
1087 }
1088 */
1089
1090 //conn.endTx(Transaction.COMMIT);
1091
1092 return flowPathsObjArray;
1093 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001094
1095 /**
1096 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1097 *
1098 * @param flowObj the object to extract the Flow Path State from.
1099 * @return the extracted Flow Path State.
1100 */
1101 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001102 //
1103 // Extract the Flow state
1104 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001105 String flowIdStr = flowObj.getFlowId();
1106 String installerIdStr = flowObj.getInstallerId();
1107 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001108 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001109 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001110 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001111
1112 if ((flowIdStr == null) ||
1113 (installerIdStr == null) ||
1114 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001115 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001116 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001117 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001118 // TODO: A work-around, becauuse of some bogus database objects
1119 return null;
1120 }
1121
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001122 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001123 flowPath.setFlowId(new FlowId(flowIdStr));
1124 flowPath.setInstallerId(new CallerId(installerIdStr));
1125 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001126 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001127 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001128 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001129 //
1130 // Extract the match conditions common for all Flow Entries
1131 //
1132 {
1133 FlowEntryMatch match = new FlowEntryMatch();
1134 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1135 if (matchEthernetFrameType != null)
1136 match.enableEthernetFrameType(matchEthernetFrameType);
1137 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1138 if (matchSrcIPv4Net != null)
1139 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1140 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1141 if (matchDstIPv4Net != null)
1142 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1143 String matchSrcMac = flowObj.getMatchSrcMac();
1144 if (matchSrcMac != null)
1145 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1146 String matchDstMac = flowObj.getMatchDstMac();
1147 if (matchDstMac != null)
1148 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1149 flowPath.setFlowEntryMatch(match);
1150 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001151
1152 //
1153 // Extract all Flow Entries
1154 //
1155 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1156 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001157 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1158 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001159 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001160 flowPath.dataPath().flowEntries().add(flowEntry);
1161 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001162
1163 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001164 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001165
1166 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001167 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1168 *
1169 * @param flowEntryObj the object to extract the Flow Entry State from.
1170 * @return the extracted Flow Entry State.
1171 */
1172 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1173 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1174 String switchDpidStr = flowEntryObj.getSwitchDpid();
1175 String userState = flowEntryObj.getUserState();
1176 String switchState = flowEntryObj.getSwitchState();
1177
1178 if ((flowEntryIdStr == null) ||
1179 (switchDpidStr == null) ||
1180 (userState == null) ||
1181 (switchState == null)) {
1182 // TODO: A work-around, becauuse of some bogus database objects
1183 return null;
1184 }
1185
1186 FlowEntry flowEntry = new FlowEntry();
1187 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1188 flowEntry.setDpid(new Dpid(switchDpidStr));
1189
1190 //
1191 // Extract the match conditions
1192 //
1193 FlowEntryMatch match = new FlowEntryMatch();
1194 Short matchInPort = flowEntryObj.getMatchInPort();
1195 if (matchInPort != null)
1196 match.enableInPort(new Port(matchInPort));
1197 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1198 if (matchEthernetFrameType != null)
1199 match.enableEthernetFrameType(matchEthernetFrameType);
1200 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1201 if (matchSrcIPv4Net != null)
1202 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1203 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1204 if (matchDstIPv4Net != null)
1205 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1206 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1207 if (matchSrcMac != null)
1208 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1209 String matchDstMac = flowEntryObj.getMatchDstMac();
1210 if (matchDstMac != null)
1211 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1212 flowEntry.setFlowEntryMatch(match);
1213
1214 //
1215 // Extract the actions
1216 //
1217 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1218 Short actionOutputPort = flowEntryObj.getActionOutput();
1219 if (actionOutputPort != null) {
1220 FlowEntryAction action = new FlowEntryAction();
1221 action.setActionOutput(new Port(actionOutputPort));
1222 actions.add(action);
1223 }
1224 flowEntry.setFlowEntryActions(actions);
1225 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1226 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1227 //
1228 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1229 // and FlowEntryErrorState.
1230 //
1231 return flowEntry;
1232 }
1233
1234 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001235 * Add and maintain a shortest-path flow.
1236 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001237 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001238 *
1239 * @param flowPath the Flow Path with the endpoints and the match
1240 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001241 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001242 */
1243 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001244 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001245 String dataPathSummaryStr = null;
1246
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001247 //
1248 // Do the shortest path computation
1249 //
1250 DataPath dataPath =
1251 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1252 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001253 if (dataPath == null) {
1254 // We need the DataPath to populate the Network MAP
1255 dataPath = new DataPath();
1256 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1257 dataPath.setDstPort(flowPath.dataPath().dstPort());
1258 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001259
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001260 // Compute the Data Path summary
1261 dataPathSummaryStr = dataPath.dataPathSummary();
1262
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001263 //
1264 // Set the incoming port matching and the outgoing port output
1265 // actions for each flow entry.
1266 //
1267 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1268 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001269 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001270 flowEntry.setFlowEntryMatch(flowEntryMatch);
1271 flowEntryMatch.enableInPort(flowEntry.inPort());
1272
1273 // Set the outgoing port output action
1274 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1275 if (flowEntryActions == null) {
1276 flowEntryActions = new ArrayList<FlowEntryAction>();
1277 flowEntry.setFlowEntryActions(flowEntryActions);
1278 }
1279 FlowEntryAction flowEntryAction = new FlowEntryAction();
1280 flowEntryAction.setActionOutput(flowEntry.outPort());
1281 flowEntryActions.add(flowEntryAction);
1282 }
1283
1284 //
1285 // Prepare the computed Flow Path
1286 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001287 FlowPath computedFlowPath = new FlowPath();
1288 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1289 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1290 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001291 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001292
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001293 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001294 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001295 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001296
1297 // TODO: Mark the flow for maintenance purpose
1298
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001299 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001300 }
1301
1302 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001303 * Reconcile a flow.
1304 *
1305 * @param flowObj the flow that needs to be reconciliated.
1306 * @param newDataPath the new data path to use.
1307 * @return true on success, otherwise false.
1308 */
1309 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1310 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1311
1312 //
1313 // Set the incoming port matching and the outgoing port output
1314 // actions for each flow entry.
1315 //
1316 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1317 // Set the incoming port matching
1318 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1319 flowEntry.setFlowEntryMatch(flowEntryMatch);
1320 flowEntryMatch.enableInPort(flowEntry.inPort());
1321
1322 // Set the outgoing port output action
1323 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1324 if (flowEntryActions == null) {
1325 flowEntryActions = new ArrayList<FlowEntryAction>();
1326 flowEntry.setFlowEntryActions(flowEntryActions);
1327 }
1328 FlowEntryAction flowEntryAction = new FlowEntryAction();
1329 flowEntryAction.setActionOutput(flowEntry.outPort());
1330 flowEntryActions.add(flowEntryAction);
1331 }
1332
1333 //
1334 // Remove the old Flow Entries, and add the new Flow Entries
1335 //
1336
1337 //
1338 // Remove the Flow Entries from the Network MAP
1339 //
1340 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1341 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1342 for (IFlowEntry flowEntryObj : flowEntries) {
1343 String dpidStr = flowEntryObj.getSwitchDpid();
1344 if (dpidStr == null)
1345 continue;
1346 Dpid dpid = new Dpid(dpidStr);
1347 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1348
1349 flowEntryObj.setUserState("FE_USER_DELETE");
1350 if (mySwitch == null) {
1351 //
1352 // Not my switch. Mark it for deletion in the Network MAP
1353 //
1354 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1355 continue;
1356 }
1357
1358 deleteFlowEntries.add(flowEntryObj);
1359
1360 //
1361 // Delete the flow entry from the switch
1362 //
1363 // flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1364 installFlowEntry(mySwitch, flowObj, flowEntryObj);
1365 // flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1366 }
1367 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
1368 flowObj.removeFlowEntry(flowEntryObj);
1369 conn.utils().removeFlowEntry(conn, flowEntryObj);
1370 }
1371
1372 //
1373 // Install the new shortest path into the Network MAP and the switches.
1374 //
1375 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1376 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1377 IFlowEntry flowEntryObj = addFlowEntry(flowObj, flowEntry);
1378 if (flowEntryObj == null) {
1379 //
1380 // TODO: Remove the "new Object[] wrapper in the statement
1381 // below after the SLF4J logger is upgraded to
1382 // Version 1.7.5
1383 //
1384 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1385 new Object[] {
1386 flowEntry.dpid(),
1387 newDataPath.srcPort(),
1388 newDataPath.dstPort()
1389 });
1390 continue;
1391 }
1392
1393 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1394 if (mySwitch == null) {
1395 // Not my switch: just add to the Network MAP
1396 continue;
1397 }
1398
1399 // Install the Flow Entry into the switch
1400 if (installFlowEntry(mySwitch, flowObj, flowEntryObj)) {
1401 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1402 }
1403 }
1404
1405 //
1406 // Set the Data Path Summary
1407 //
1408 String dataPathSummaryStr = newDataPath.dataPathSummary();
1409 flowObj.setDataPathSummary(dataPathSummaryStr);
1410
1411 return true;
1412 }
1413
1414 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001415 * Reconcile all flows in a set.
1416 *
1417 * @param flowObjSet the set of flows that need to be reconciliated.
1418 */
1419 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1420 if (! flowObjSet.iterator().hasNext())
1421 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001422 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423 }
1424
1425 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001426 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001427 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001428 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001429 * @param flowObj the flow path object for the flow entry to install.
1430 * @param flowEntryObj the flow entry object to install.
1431 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001432 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001433 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1434 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001435 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1436 if (flowEntryIdStr == null)
1437 return false;
1438 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001439 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001440 if (userState == null)
1441 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001442
1443 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001444 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001445 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001446 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1447 .getMessage(OFType.FLOW_MOD);
1448 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001449
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001450 short flowModCommand = OFFlowMod.OFPFC_ADD;
1451 if (userState.equals("FE_USER_ADD")) {
1452 flowModCommand = OFFlowMod.OFPFC_ADD;
1453 } else if (userState.equals("FE_USER_MODIFY")) {
1454 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1455 } else if (userState.equals("FE_USER_DELETE")) {
1456 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1457 } else {
1458 // Unknown user state. Ignore the entry
1459 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1460 flowEntryId.toString(), userState);
1461 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001462 }
1463
1464 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001465 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001466 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001467 // NOTE: The Flow matching conditions common for all Flow Entries are
1468 // used ONLY if a Flow Entry does NOT have the corresponding matching
1469 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001470 //
1471 OFMatch match = new OFMatch();
1472 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001473
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001474 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001475 Short matchInPort = flowEntryObj.getMatchInPort();
1476 if (matchInPort != null) {
1477 match.setInputPort(matchInPort);
1478 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1479 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001480
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001481 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001482 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1483 if (matchEthernetFrameType == null)
1484 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1485 if (matchEthernetFrameType != null) {
1486 match.setDataLayerType(matchEthernetFrameType);
1487 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1488 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001489
1490 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001491 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1492 if (matchSrcIPv4Net == null)
1493 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1494 if (matchSrcIPv4Net != null) {
1495 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1496 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001497
1498 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001499 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1500 if (matchDstIPv4Net == null)
1501 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1502 if (matchDstIPv4Net != null) {
1503 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1504 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001505
1506 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001507 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1508 if (matchSrcMac == null)
1509 matchSrcMac = flowObj.getMatchSrcMac();
1510 if (matchSrcMac != null) {
1511 match.setDataLayerSource(matchSrcMac);
1512 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1513 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001514
1515 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001516 String matchDstMac = flowEntryObj.getMatchDstMac();
1517 if (matchDstMac == null)
1518 matchDstMac = flowObj.getMatchDstMac();
1519 if (matchDstMac != null) {
1520 match.setDataLayerDestination(matchDstMac);
1521 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1522 }
1523
1524 //
1525 // Fetch the actions
1526 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001527 // TODO: For now we support only the "OUTPUT" actions.
1528 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001529 List<OFAction> actions = new ArrayList<OFAction>();
1530 Short actionOutputPort = flowEntryObj.getActionOutput();
1531 if (actionOutputPort != null) {
1532 OFActionOutput action = new OFActionOutput();
1533 // XXX: The max length is hard-coded for now
1534 action.setMaxLength((short)0xffff);
1535 action.setPort(actionOutputPort);
1536 actions.add(action);
1537 }
1538
1539 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1540 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1541 .setPriority(PRIORITY_DEFAULT)
1542 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1543 .setCookie(cookie)
1544 .setCommand(flowModCommand)
1545 .setMatch(match)
1546 .setActions(actions)
1547 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1548 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1549 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1550 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1551 if (actionOutputPort != null)
1552 fm.setOutPort(actionOutputPort);
1553 }
1554
1555 //
1556 // TODO: Set the following flag
1557 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1558 // See method ForwardingBase::pushRoute()
1559 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001560
1561 //
1562 // Write the message to the switch
1563 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001564 log.debug("MEASUREMENT: Installing flow entry " + userState +
1565 " into switch DPID: " +
1566 mySwitch.getStringId() +
1567 " flowEntryId: " + flowEntryId.toString() +
1568 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1569 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1570 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001571 try {
1572 messageDamper.write(mySwitch, fm, null);
1573 mySwitch.flush();
1574 //
1575 // TODO: We should use the OpenFlow Barrier mechanism
1576 // to check for errors, and update the SwitchState
1577 // for a flow entry after the Barrier message is
1578 // is received.
1579 //
1580 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1581 } catch (IOException e) {
1582 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001583 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001584 }
1585
1586 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001587 }
1588
1589 /**
1590 * Install a Flow Entry on a switch.
1591 *
1592 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001593 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001594 * @param flowEntry the flow entry to install.
1595 * @return true on success, otherwise false.
1596 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001597 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1598 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001599 //
1600 // Create the OpenFlow Flow Modification Entry to push
1601 //
1602 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1603 .getMessage(OFType.FLOW_MOD);
1604 long cookie = flowEntry.flowEntryId().value();
1605
1606 short flowModCommand = OFFlowMod.OFPFC_ADD;
1607 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1608 flowModCommand = OFFlowMod.OFPFC_ADD;
1609 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1610 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1611 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1612 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1613 } else {
1614 // Unknown user state. Ignore the entry
1615 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1616 flowEntry.flowEntryId().toString(),
1617 flowEntry.flowEntryUserState());
1618 return false;
1619 }
1620
1621 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001622 // Fetch the match conditions.
1623 //
1624 // NOTE: The Flow matching conditions common for all Flow Entries are
1625 // used ONLY if a Flow Entry does NOT have the corresponding matching
1626 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001627 //
1628 OFMatch match = new OFMatch();
1629 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001630 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1631 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1632
1633 // Match the Incoming Port
1634 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001635 if (matchInPort != null) {
1636 match.setInputPort(matchInPort.value());
1637 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1638 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001639
1640 // Match the Ethernet Frame Type
1641 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1642 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1643 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1644 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001645 if (matchEthernetFrameType != null) {
1646 match.setDataLayerType(matchEthernetFrameType);
1647 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1648 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001649
1650 // Match the Source IPv4 Network prefix
1651 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1652 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1653 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1654 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001655 if (matchSrcIPv4Net != null) {
1656 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1657 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001658
1659 // Natch the Destination IPv4 Network prefix
1660 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1661 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1662 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1663 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001664 if (matchDstIPv4Net != null) {
1665 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1666 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001667
1668 // Match the Source MAC address
1669 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1670 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1671 matchSrcMac = flowPathMatch.srcMac();
1672 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673 if (matchSrcMac != null) {
1674 match.setDataLayerSource(matchSrcMac.toString());
1675 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1676 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001677
1678 // Match the Destination MAC address
1679 MACAddress matchDstMac = flowEntryMatch.dstMac();
1680 if ((matchDstMac == null) && (flowPathMatch != null)) {
1681 matchDstMac = flowPathMatch.dstMac();
1682 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001683 if (matchDstMac != null) {
1684 match.setDataLayerDestination(matchDstMac.toString());
1685 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1686 }
1687
1688 //
1689 // Fetch the actions
1690 //
1691 // TODO: For now we support only the "OUTPUT" actions.
1692 //
1693 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1694 List<OFAction> actions = new ArrayList<OFAction>();
1695 ArrayList<FlowEntryAction> flowEntryActions =
1696 flowEntry.flowEntryActions();
1697 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1698 FlowEntryAction.ActionOutput actionOutput =
1699 flowEntryAction.actionOutput();
1700 if (actionOutput != null) {
1701 short actionOutputPort = actionOutput.port().value();
1702 OFActionOutput action = new OFActionOutput();
1703 // XXX: The max length is hard-coded for now
1704 action.setMaxLength((short)0xffff);
1705 action.setPort(actionOutputPort);
1706 actions.add(action);
1707 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1708 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1709 fm.setOutPort(actionOutputPort);
1710 }
1711 }
1712 }
1713
1714 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1715 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1716 .setPriority(PRIORITY_DEFAULT)
1717 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1718 .setCookie(cookie)
1719 .setCommand(flowModCommand)
1720 .setMatch(match)
1721 .setActions(actions)
1722 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1723
1724 //
1725 // TODO: Set the following flag
1726 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1727 // See method ForwardingBase::pushRoute()
1728 //
1729
1730 //
1731 // Write the message to the switch
1732 //
1733 try {
1734 messageDamper.write(mySwitch, fm, null);
1735 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001736 //
1737 // TODO: We should use the OpenFlow Barrier mechanism
1738 // to check for errors, and update the SwitchState
1739 // for a flow entry after the Barrier message is
1740 // is received.
1741 //
1742 // TODO: The FlowEntry Object in Titan should be set
1743 // to FE_SWITCH_UPDATED.
1744 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001745 } catch (IOException e) {
1746 log.error("Failure writing flow mod from network map", e);
1747 return false;
1748 }
1749 return true;
1750 }
1751
1752 /**
1753 * Remove a Flow Entry from a switch.
1754 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001755 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001756 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001757 * @param flowEntry the flow entry to remove.
1758 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001759 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001760 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1761 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001762 //
1763 // The installFlowEntry() method implements both installation
1764 // and removal of flow entries.
1765 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001766 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001767 }
1768
1769 /**
1770 * Install a Flow Entry on a remote controller.
1771 *
1772 * TODO: We need it now: Jono
1773 * - For now it will make a REST call to the remote controller.
1774 * - Internally, it needs to know the name of the remote controller.
1775 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001776 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001777 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001778 * @return true on success, otherwise false.
1779 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001780 public boolean installRemoteFlowEntry(FlowPath flowPath,
1781 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001782 // TODO: We need it now: Jono
1783 // - For now it will make a REST call to the remote controller.
1784 // - Internally, it needs to know the name of the remote controller.
1785 return true;
1786 }
1787
1788 /**
1789 * Remove a flow entry on a remote controller.
1790 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001791 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001792 * @param flowEntry the flow entry to remove.
1793 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001794 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001795 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1796 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001797 //
1798 // The installRemoteFlowEntry() method implements both installation
1799 // and removal of flow entries.
1800 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001801 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001802 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001803}