blob: fc942607e036f77c2bc77391a0d483ad20c73515 [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
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700182 //
183 // Process the Flow Entries that need to be added
184 //
185 for (IFlowEntry flowEntryObj : addFlowEntries) {
186 IFlowPath flowObj =
187 conn.utils().getFlowPathByFlowEntry(conn,
188 flowEntryObj);
189 if (flowObj == null)
190 continue; // Should NOT happen
191 if (flowObj.getFlowId() == null)
192 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700193
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700194 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700195 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000196 if (mySwitch == null)
197 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700198 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800199 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200
201 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000202 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700203 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204 //
205 // TODO: We should use the OpenFlow Barrier mechanism
206 // to check for errors, and delete the Flow Entries after the
207 // Barrier message is received.
208 //
209 while (! deleteFlowEntries.isEmpty()) {
210 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
211 IFlowPath flowObj =
212 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
213 if (flowObj == null) {
214 log.debug("Did not find FlowPath to be deleted");
215 continue;
216 }
217 flowObj.removeFlowEntry(flowEntryObj);
218 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000219 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700220
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700221 //
222 // Fetch and recompute the Shortest Path for those
223 // Flow Paths this controller is responsible for.
224 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700225 topoRouteService.prepareShortestPathTopo();
226 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700227 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700228 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700229 if (flowPathObj == null)
230 continue;
231 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
232 if (dataPathSummaryStr == null)
233 continue; // Could be invalid entry?
234 if (dataPathSummaryStr.isEmpty())
235 continue; // No need to maintain this flow
236
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700237 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000238 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700239 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700240 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700241 //
242 // Use the source DPID as a heuristic to decide
243 // which controller is responsible for maintaining the
244 // shortest path.
245 // NOTE: This heuristic is error-prone: if the switch
246 // goes away and no controller is responsible for that
247 // switch, then the original Flow Path is not cleaned-up
248 //
249 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
250 if (mySwitch == null)
251 continue; // Ignore: not my responsibility
252
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000253 //
254 // Test whether we need to complete the Flow cleanup,
255 // if the Flow has been deleted by the user.
256 //
257 String flowUserState = flowPathObj.getUserState();
258 if ((flowUserState != null)
259 && flowUserState.equals("FE_USER_DELETE")) {
260 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
261 boolean empty = true; // TODO: an ugly hack
262 for (IFlowEntry flowEntryObj : flowEntries) {
263 empty = false;
264 break;
265 }
266 if (empty)
267 deleteFlows.add(flowPathObj);
268 }
269
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000270 // Fetch the fields needed to recompute the shortest path
271 Short srcPortShort = flowPathObj.getSrcPort();
272 String dstDpidStr = flowPathObj.getDstSwitch();
273 Short dstPortShort = flowPathObj.getDstPort();
274 if ((srcPortShort == null) ||
275 (dstDpidStr == null) ||
276 (dstPortShort == null)) {
277 continue;
278 }
279
280 Port srcPort = new Port(srcPortShort);
281 Dpid dstDpid = new Dpid(dstDpidStr);
282 Port dstPort = new Port(dstPortShort);
283 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
284 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
285
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700286 counterMyFlowPaths++;
287
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700288 //
289 // NOTE: Using here the regular getShortestPath() method
290 // won't work here, because that method calls internally
291 // "conn.endTx(Transaction.COMMIT)", and that will
292 // invalidate all handlers to the Titan database.
293 // If we want to experiment with calling here
294 // getShortestPath(), we need to refactor that code
295 // to avoid closing the transaction.
296 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700297 DataPath dataPath =
298 topoRouteService.getTopoShortestPath(srcSwitchPort,
299 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000300 if (dataPath == null) {
301 // We need the DataPath to compare the paths
302 dataPath = new DataPath();
303 dataPath.setSrcPort(srcSwitchPort);
304 dataPath.setDstPort(dstSwitchPort);
305 }
306
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307 String newDataPathSummaryStr = dataPath.dataPathSummary();
308 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
309 continue; // Nothing changed
310
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700311 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700312 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000313
314 //
315 // Delete all leftover Flows marked for deletion from the
316 // Network MAP.
317 //
318 while (! deleteFlows.isEmpty()) {
319 IFlowPath flowPathObj = deleteFlows.poll();
320 conn.utils().removeFlowPath(conn, flowPathObj);
321 }
322
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700323 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700324
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800325 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700326
327 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700328 long estimatedTime =
329 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700330 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
331 (double)estimatedTime / 1000000000 + " sec";
332 log.debug(logMsg);
333 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700334
335 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700336 double rate = 0.0;
337 if (estimatedTime > 0)
338 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
339 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
340 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
341 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
342 counterAllFlowPaths + " MyFlowPaths: " +
343 counterMyFlowPaths + " in " +
344 (double)estimatedTime / 1000000000 + " sec: " +
345 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700346 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800347 }
348 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700349
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700350 final ScheduledFuture<?> mapReaderHandle =
351 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800352
353 @Override
354 public void init(String conf) {
355 conn = GraphDBConnection.getInstance(conf);
356 }
357
358 public void finalize() {
359 close();
360 }
361
362 @Override
363 public void close() {
364 conn.close();
365 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800366
367 @Override
368 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
369 Collection<Class<? extends IFloodlightService>> l =
370 new ArrayList<Class<? extends IFloodlightService>>();
371 l.add(IFlowService.class);
372 return l;
373 }
374
375 @Override
376 public Map<Class<? extends IFloodlightService>, IFloodlightService>
377 getServiceImpls() {
378 Map<Class<? extends IFloodlightService>,
379 IFloodlightService> m =
380 new HashMap<Class<? extends IFloodlightService>,
381 IFloodlightService>();
382 m.put(IFlowService.class, this);
383 return m;
384 }
385
386 @Override
387 public Collection<Class<? extends IFloodlightService>>
388 getModuleDependencies() {
389 Collection<Class<? extends IFloodlightService>> l =
390 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800391 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700392 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800393 l.add(IRestApiService.class);
394 return l;
395 }
396
397 @Override
398 public void init(FloodlightModuleContext context)
399 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700400 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800401 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700402 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800403 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800404 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
405 EnumSet.of(OFType.FLOW_MOD),
406 OFMESSAGE_DAMPER_TIMEOUT);
407 // TODO: An ugly hack!
408 String conf = "/tmp/cassandra.titan";
409 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800410 }
411
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000412 private long getNextFlowEntryId() {
413 //
414 // Generate the next Flow Entry ID.
415 // NOTE: For now, the higher 32 bits are random, and
416 // the lower 32 bits are sequential.
417 // In the future, we need a better allocation mechanism.
418 //
419 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
420 nextFlowEntryIdPrefix = randomGenerator.nextInt();
421 nextFlowEntryIdSuffix = 0;
422 } else {
423 nextFlowEntryIdSuffix++;
424 }
425 long result = (long)nextFlowEntryIdPrefix << 32;
426 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
427 return result;
428 }
429
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800430 @Override
431 public void startUp(FloodlightModuleContext context) {
432 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700433
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000434 // Initialize the Flow Entry ID generator
435 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800436 }
437
438 /**
439 * Add a flow.
440 *
441 * Internally, ONOS will automatically register the installer for
442 * receiving Flow Path Notifications for that path.
443 *
444 * @param flowPath the Flow Path to install.
445 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700446 * @param dataPathSummaryStr the data path summary string if the added
447 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800448 * @return true on success, otherwise false.
449 */
450 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700451 public boolean addFlow(FlowPath flowPath, FlowId flowId,
452 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700453 /*
454 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700455 if (flowPath.flowId().value() == measurementFlowId) {
456 modifiedMeasurementFlowTime = System.nanoTime();
457 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700458 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800459
460 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000461 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800462 try {
463 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
464 != null) {
465 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
466 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000467 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800468 } else {
469 flowObj = conn.utils().newFlowPath(conn);
470 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
471 flowPath.flowId().toString());
472 }
473 } catch (Exception e) {
474 // TODO: handle exceptions
475 conn.endTx(Transaction.ROLLBACK);
476 log.error(":addFlow FlowId:{} failed",
477 flowPath.flowId().toString());
478 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700479 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000480 log.error(":addFlow FlowId:{} failed: Flow object not created",
481 flowPath.flowId().toString());
482 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800483 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700484 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800485
486 //
487 // Set the Flow key:
488 // - flowId
489 //
490 flowObj.setFlowId(flowPath.flowId().toString());
491 flowObj.setType("flow");
492
493 //
494 // Set the Flow attributes:
495 // - flowPath.installerId()
496 // - flowPath.dataPath().srcPort()
497 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700498 // - flowPath.matchEthernetFrameType()
499 // - flowPath.matchSrcIPv4Net()
500 // - flowPath.matchDstIPv4Net()
501 // - flowPath.matchSrcMac()
502 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800503 //
504 flowObj.setInstallerId(flowPath.installerId().toString());
505 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
506 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
507 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
508 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700509 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
510 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
511 }
512 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
513 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
514 }
515 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
516 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
517 }
518 if (flowPath.flowEntryMatch().matchSrcMac()) {
519 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
520 }
521 if (flowPath.flowEntryMatch().matchDstMac()) {
522 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
523 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800524
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700525 if (dataPathSummaryStr != null) {
526 flowObj.setDataPathSummary(dataPathSummaryStr);
527 } else {
528 flowObj.setDataPathSummary("");
529 }
530
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000531 if (found)
532 flowObj.setUserState("FE_USER_MODIFY");
533 else
534 flowObj.setUserState("FE_USER_ADD");
535
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800536 // Flow edges:
537 // HeadFE
538
539
540 //
541 // Flow Entries:
542 // flowPath.dataPath().flowEntries()
543 //
544 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700545 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000546 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800547 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700548 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800549 }
550 conn.endTx(Transaction.COMMIT);
551
552 //
553 // TODO: We need a proper Flow ID allocation mechanism.
554 //
555 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700556
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800557 return true;
558 }
559
560 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700561 * Add a flow entry to the Network MAP.
562 *
563 * @param flowObj the corresponding Flow Path object for the Flow Entry.
564 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700565 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700566 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700567 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700568 // Flow edges
569 // HeadFE (TODO)
570
571 //
572 // Assign the FlowEntry ID.
573 //
574 if ((flowEntry.flowEntryId() == null) ||
575 (flowEntry.flowEntryId().value() == 0)) {
576 long id = getNextFlowEntryId();
577 flowEntry.setFlowEntryId(new FlowEntryId(id));
578 }
579
580 IFlowEntry flowEntryObj = null;
581 boolean found = false;
582 try {
583 if ((flowEntryObj =
584 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
585 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
586 flowEntry.flowEntryId().toString());
587 found = true;
588 } else {
589 flowEntryObj = conn.utils().newFlowEntry(conn);
590 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
591 flowEntry.flowEntryId().toString());
592 }
593 } catch (Exception e) {
594 log.error(":addFlow FlowEntryId:{} failed",
595 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700596 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700597 }
598 if (flowEntryObj == null) {
599 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
600 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700601 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700602 }
603
604 //
605 // Set the Flow Entry key:
606 // - flowEntry.flowEntryId()
607 //
608 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
609 flowEntryObj.setType("flow_entry");
610
611 //
612 // Set the Flow Entry Edges and attributes:
613 // - Switch edge
614 // - InPort edge
615 // - OutPort edge
616 //
617 // - flowEntry.flowEntryMatch()
618 // - flowEntry.flowEntryActions()
619 // - flowEntry.dpid()
620 // - flowEntry.flowEntryUserState()
621 // - flowEntry.flowEntrySwitchState()
622 // - flowEntry.flowEntryErrorState()
623 // - flowEntry.matchInPort()
624 // - flowEntry.matchEthernetFrameType()
625 // - flowEntry.matchSrcIPv4Net()
626 // - flowEntry.matchDstIPv4Net()
627 // - flowEntry.matchSrcMac()
628 // - flowEntry.matchDstMac()
629 // - flowEntry.actionOutput()
630 //
631 ISwitchObject sw =
632 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
633 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
634 flowEntryObj.setSwitch(sw);
635 if (flowEntry.flowEntryMatch().matchInPort()) {
636 IPortObject inport =
637 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
638 flowEntry.flowEntryMatch().inPort().value());
639 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
640 flowEntryObj.setInPort(inport);
641 }
642 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
643 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
644 }
645 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
646 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
647 }
648 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
649 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
650 }
651 if (flowEntry.flowEntryMatch().matchSrcMac()) {
652 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
653 }
654 if (flowEntry.flowEntryMatch().matchDstMac()) {
655 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
656 }
657
658 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
659 if (fa.actionOutput() != null) {
660 IPortObject outport =
661 conn.utils().searchPort(conn,
662 flowEntry.dpid().toString(),
663 fa.actionOutput().port().value());
664 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
665 flowEntryObj.setOutPort(outport);
666 }
667 }
668 // TODO: Hacks with hard-coded state names!
669 if (found)
670 flowEntryObj.setUserState("FE_USER_MODIFY");
671 else
672 flowEntryObj.setUserState("FE_USER_ADD");
673 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
674 //
675 // TODO: Take care of the FlowEntryErrorState.
676 //
677
678 // Flow Entries edges:
679 // Flow
680 // NextFE (TODO)
681 if (! found) {
682 flowObj.addFlowEntry(flowEntryObj);
683 flowEntryObj.setFlow(flowObj);
684 }
685
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700686 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700687 }
688
689 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800690 * Delete a previously added flow.
691 *
692 * @param flowId the Flow ID of the flow to delete.
693 * @return true on success, otherwise false.
694 */
695 @Override
696 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700697 /*
698 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700699 if (flowId.value() == measurementFlowId) {
700 modifiedMeasurementFlowTime = System.nanoTime();
701 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700702 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700703
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704 IFlowPath flowObj = null;
705 //
706 // We just mark the entries for deletion,
707 // and let the switches remove each individual entry after
708 // it has been removed from the switches.
709 //
710 try {
711 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
712 != null) {
713 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
714 flowId.toString());
715 } else {
716 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
717 flowId.toString());
718 }
719 } catch (Exception e) {
720 // TODO: handle exceptions
721 conn.endTx(Transaction.ROLLBACK);
722 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
723 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700724 if (flowObj == null) {
725 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800726 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700727 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800728
729 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000730 // Find and mark for deletion all Flow Entries,
731 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800732 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000733 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800734 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
735 boolean empty = true; // TODO: an ugly hack
736 for (IFlowEntry flowEntryObj : flowEntries) {
737 empty = false;
738 // flowObj.removeFlowEntry(flowEntryObj);
739 // conn.utils().removeFlowEntry(conn, flowEntryObj);
740 flowEntryObj.setUserState("FE_USER_DELETE");
741 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
742 }
743 // Remove from the database empty flows
744 if (empty)
745 conn.utils().removeFlowPath(conn, flowObj);
746 conn.endTx(Transaction.COMMIT);
747
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800748 return true;
749 }
750
751 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700752 * Clear the state for a previously added flow.
753 *
754 * @param flowId the Flow ID of the flow to clear.
755 * @return true on success, otherwise false.
756 */
757 @Override
758 public boolean clearFlow(FlowId flowId) {
759 IFlowPath flowObj = null;
760 try {
761 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
762 != null) {
763 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
764 flowId.toString());
765 } else {
766 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
767 flowId.toString());
768 }
769 } catch (Exception e) {
770 // TODO: handle exceptions
771 conn.endTx(Transaction.ROLLBACK);
772 log.error(":clearFlow FlowId:{} failed", flowId.toString());
773 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700774 if (flowObj == null) {
775 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700776 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700777 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700778
779 //
780 // Remove all Flow Entries
781 //
782 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
783 for (IFlowEntry flowEntryObj : flowEntries) {
784 flowObj.removeFlowEntry(flowEntryObj);
785 conn.utils().removeFlowEntry(conn, flowEntryObj);
786 }
787 // Remove the Flow itself
788 conn.utils().removeFlowPath(conn, flowObj);
789 conn.endTx(Transaction.COMMIT);
790
791 return true;
792 }
793
794 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800795 * Get a previously added flow.
796 *
797 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800798 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800799 */
800 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800801 public FlowPath getFlow(FlowId flowId) {
802 IFlowPath flowObj = null;
803 try {
804 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
805 != null) {
806 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
807 flowId.toString());
808 } else {
809 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
810 flowId.toString());
811 }
812 } catch (Exception e) {
813 // TODO: handle exceptions
814 conn.endTx(Transaction.ROLLBACK);
815 log.error(":getFlow FlowId:{} failed", flowId.toString());
816 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700817 if (flowObj == null) {
818 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800819 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700820 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800821
822 //
823 // Extract the Flow state
824 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800825 FlowPath flowPath = extractFlowPath(flowObj);
826 conn.endTx(Transaction.COMMIT);
827
828 return flowPath;
829 }
830
831 /**
832 * Get all previously added flows by a specific installer for a given
833 * data path endpoints.
834 *
835 * @param installerId the Caller ID of the installer of the flow to get.
836 * @param dataPathEndpoints the data path endpoints of the flow to get.
837 * @return the Flow Paths if found, otherwise null.
838 */
839 @Override
840 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
841 DataPathEndpoints dataPathEndpoints) {
842 //
843 // TODO: The implementation below is not optimal:
844 // We fetch all flows, and then return only the subset that match
845 // the query conditions.
846 // We should use the appropriate Titan/Gremlin query to filter-out
847 // the flows as appropriate.
848 //
849 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700850 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800851
852 if (allFlows == null) {
853 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700854 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800855 }
856
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800857 for (FlowPath flow : allFlows) {
858 //
859 // TODO: String-based comparison is sub-optimal.
860 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800861 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800862 //
863 if (! flow.installerId().toString().equals(installerId.toString()))
864 continue;
865 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
866 continue;
867 }
868 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
869 continue;
870 }
871 flowPaths.add(flow);
872 }
873
874 if (flowPaths.isEmpty()) {
875 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800876 } else {
877 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
878 }
879
880 return flowPaths;
881 }
882
883 /**
884 * Get all installed flows by all installers for given data path endpoints.
885 *
886 * @param dataPathEndpoints the data path endpoints of the flows to get.
887 * @return the Flow Paths if found, otherwise null.
888 */
889 @Override
890 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
891 //
892 // TODO: The implementation below is not optimal:
893 // We fetch all flows, and then return only the subset that match
894 // the query conditions.
895 // We should use the appropriate Titan/Gremlin query to filter-out
896 // the flows as appropriate.
897 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700898 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
899 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800900
901 if (allFlows == null) {
902 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700903 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800904 }
905
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800906 for (FlowPath flow : allFlows) {
907 //
908 // TODO: String-based comparison is sub-optimal.
909 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800910 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800911 //
912 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
913 continue;
914 }
915 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
916 continue;
917 }
918 flowPaths.add(flow);
919 }
920
921 if (flowPaths.isEmpty()) {
922 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800923 } else {
924 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
925 }
926
927 return flowPaths;
928 }
929
930 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700931 * Get summary of all installed flows by all installers in a given range
932 *
933 * @param flowId the data path endpoints of the flows to get.
934 * @param maxFlows: the maximum number of flows to be returned
935 * @return the Flow Paths if found, otherwise null.
936 */
937 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700938 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700939
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700940 // TODO: The implementation below is not optimal:
941 // We fetch all flows, and then return only the subset that match
942 // the query conditions.
943 // We should use the appropriate Titan/Gremlin query to filter-out
944 // the flows as appropriate.
945 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700946 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700947
Jonathan Hart01f2d272013-04-04 20:03:46 -0700948 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
949
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700950 Collections.sort(flowPathsWithoutFlowEntries,
951 new Comparator<IFlowPath>(){
952 @Override
953 public int compare(IFlowPath first, IFlowPath second) {
954 // TODO Auto-generated method stub
955 long result = new FlowId(first.getFlowId()).value()
956 - new FlowId(second.getFlowId()).value();
957 if (result > 0) return 1;
958 else if (result < 0) return -1;
959 else return 0;
960 }
961 }
962 );
963
Jonathan Hart01f2d272013-04-04 20:03:46 -0700964 return flowPathsWithoutFlowEntries;
965
966 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700967 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -0700968
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700969 if (allFlows == null) {
970 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700971 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700972 }
973
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700974 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700975
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700976 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700977 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700978
Pavlin Radoslavov96b43422013-04-04 19:14:56 -0700979 // start from desired flowId
980 if (flow.flowId().value() < flowId.value()) {
981 continue;
982 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700983
984 // Summarize by making null flow entry fields that are not relevant to report
985 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
986 flowEntry.setFlowEntryActions(null);
987 flowEntry.setFlowEntryMatch(null);
988 }
989
990 flowPaths.add(flow);
991 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
992 break;
993 }
994 }
995
996 if (flowPaths.isEmpty()) {
997 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700998 } else {
999 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1000 }
1001
1002 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001003 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001004 }
1005
1006 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001007 * Get all installed flows by all installers.
1008 *
1009 * @return the Flow Paths if found, otherwise null.
1010 */
1011 @Override
1012 public ArrayList<FlowPath> getAllFlows() {
1013 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001014 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001015
1016 try {
1017 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1018 log.debug("Get all FlowPaths: found FlowPaths");
1019 } else {
1020 log.debug("Get all FlowPaths: no FlowPaths found");
1021 }
1022 } catch (Exception e) {
1023 // TODO: handle exceptions
1024 conn.endTx(Transaction.ROLLBACK);
1025 log.error(":getAllFlowPaths failed");
1026 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001027 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1028 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001029 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001030 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001031
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001032 for (IFlowPath flowObj : flowPathsObj) {
1033 //
1034 // Extract the Flow state
1035 //
1036 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001037 if (flowPath != null)
1038 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001039 }
1040
1041 conn.endTx(Transaction.COMMIT);
1042
1043 return flowPaths;
1044 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001045
1046 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1047 Iterable<IFlowPath> flowPathsObj = null;
1048 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1049 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1050
1051 try {
1052 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1053 log.debug("Get all FlowPaths: found FlowPaths");
1054 } else {
1055 log.debug("Get all FlowPaths: no FlowPaths found");
1056 }
1057 } catch (Exception e) {
1058 // TODO: handle exceptions
1059 conn.endTx(Transaction.ROLLBACK);
1060 log.error(":getAllFlowPaths failed");
1061 }
1062 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1063 return new ArrayList<IFlowPath>(); // No Flows found
1064 }
1065
1066 for (IFlowPath flowObj : flowPathsObj){
1067 flowPathsObjArray.add(flowObj);
1068 }
1069 /*
1070 for (IFlowPath flowObj : flowPathsObj) {
1071 //
1072 // Extract the Flow state
1073 //
1074 FlowPath flowPath = extractFlowPath(flowObj);
1075 if (flowPath != null)
1076 flowPaths.add(flowPath);
1077 }
1078 */
1079
1080 //conn.endTx(Transaction.COMMIT);
1081
1082 return flowPathsObjArray;
1083 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001084
1085 /**
1086 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1087 *
1088 * @param flowObj the object to extract the Flow Path State from.
1089 * @return the extracted Flow Path State.
1090 */
1091 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001092 //
1093 // Extract the Flow state
1094 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001095 String flowIdStr = flowObj.getFlowId();
1096 String installerIdStr = flowObj.getInstallerId();
1097 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001098 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001099 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001100 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001101
1102 if ((flowIdStr == null) ||
1103 (installerIdStr == null) ||
1104 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001105 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001106 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001107 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001108 // TODO: A work-around, becauuse of some bogus database objects
1109 return null;
1110 }
1111
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001112 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001113 flowPath.setFlowId(new FlowId(flowIdStr));
1114 flowPath.setInstallerId(new CallerId(installerIdStr));
1115 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001116 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001117 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001118 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001119 //
1120 // Extract the match conditions common for all Flow Entries
1121 //
1122 {
1123 FlowEntryMatch match = new FlowEntryMatch();
1124 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1125 if (matchEthernetFrameType != null)
1126 match.enableEthernetFrameType(matchEthernetFrameType);
1127 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1128 if (matchSrcIPv4Net != null)
1129 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1130 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1131 if (matchDstIPv4Net != null)
1132 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1133 String matchSrcMac = flowObj.getMatchSrcMac();
1134 if (matchSrcMac != null)
1135 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1136 String matchDstMac = flowObj.getMatchDstMac();
1137 if (matchDstMac != null)
1138 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1139 flowPath.setFlowEntryMatch(match);
1140 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001141
1142 //
1143 // Extract all Flow Entries
1144 //
1145 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1146 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001147 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1148 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001149 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001150 flowPath.dataPath().flowEntries().add(flowEntry);
1151 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001152
1153 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001154 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001155
1156 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001157 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1158 *
1159 * @param flowEntryObj the object to extract the Flow Entry State from.
1160 * @return the extracted Flow Entry State.
1161 */
1162 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1163 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1164 String switchDpidStr = flowEntryObj.getSwitchDpid();
1165 String userState = flowEntryObj.getUserState();
1166 String switchState = flowEntryObj.getSwitchState();
1167
1168 if ((flowEntryIdStr == null) ||
1169 (switchDpidStr == null) ||
1170 (userState == null) ||
1171 (switchState == null)) {
1172 // TODO: A work-around, becauuse of some bogus database objects
1173 return null;
1174 }
1175
1176 FlowEntry flowEntry = new FlowEntry();
1177 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1178 flowEntry.setDpid(new Dpid(switchDpidStr));
1179
1180 //
1181 // Extract the match conditions
1182 //
1183 FlowEntryMatch match = new FlowEntryMatch();
1184 Short matchInPort = flowEntryObj.getMatchInPort();
1185 if (matchInPort != null)
1186 match.enableInPort(new Port(matchInPort));
1187 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1188 if (matchEthernetFrameType != null)
1189 match.enableEthernetFrameType(matchEthernetFrameType);
1190 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1191 if (matchSrcIPv4Net != null)
1192 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1193 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1194 if (matchDstIPv4Net != null)
1195 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1196 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1197 if (matchSrcMac != null)
1198 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1199 String matchDstMac = flowEntryObj.getMatchDstMac();
1200 if (matchDstMac != null)
1201 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1202 flowEntry.setFlowEntryMatch(match);
1203
1204 //
1205 // Extract the actions
1206 //
1207 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1208 Short actionOutputPort = flowEntryObj.getActionOutput();
1209 if (actionOutputPort != null) {
1210 FlowEntryAction action = new FlowEntryAction();
1211 action.setActionOutput(new Port(actionOutputPort));
1212 actions.add(action);
1213 }
1214 flowEntry.setFlowEntryActions(actions);
1215 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1216 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1217 //
1218 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1219 // and FlowEntryErrorState.
1220 //
1221 return flowEntry;
1222 }
1223
1224 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001225 * Add and maintain a shortest-path flow.
1226 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001227 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001228 *
1229 * @param flowPath the Flow Path with the endpoints and the match
1230 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001231 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001232 */
1233 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001234 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001235 String dataPathSummaryStr = null;
1236
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001237 //
1238 // Do the shortest path computation
1239 //
1240 DataPath dataPath =
1241 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1242 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001243 if (dataPath == null) {
1244 // We need the DataPath to populate the Network MAP
1245 dataPath = new DataPath();
1246 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1247 dataPath.setDstPort(flowPath.dataPath().dstPort());
1248 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001249
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001250 // Compute the Data Path summary
1251 dataPathSummaryStr = dataPath.dataPathSummary();
1252
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001253 //
1254 // Set the incoming port matching and the outgoing port output
1255 // actions for each flow entry.
1256 //
1257 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1258 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001259 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001260 flowEntry.setFlowEntryMatch(flowEntryMatch);
1261 flowEntryMatch.enableInPort(flowEntry.inPort());
1262
1263 // Set the outgoing port output action
1264 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1265 if (flowEntryActions == null) {
1266 flowEntryActions = new ArrayList<FlowEntryAction>();
1267 flowEntry.setFlowEntryActions(flowEntryActions);
1268 }
1269 FlowEntryAction flowEntryAction = new FlowEntryAction();
1270 flowEntryAction.setActionOutput(flowEntry.outPort());
1271 flowEntryActions.add(flowEntryAction);
1272 }
1273
1274 //
1275 // Prepare the computed Flow Path
1276 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001277 FlowPath computedFlowPath = new FlowPath();
1278 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1279 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1280 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001281 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001282
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001283 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001284 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001285 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001286
1287 // TODO: Mark the flow for maintenance purpose
1288
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001289 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001290 }
1291
1292 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001293 * Reconcile a flow.
1294 *
1295 * @param flowObj the flow that needs to be reconciliated.
1296 * @param newDataPath the new data path to use.
1297 * @return true on success, otherwise false.
1298 */
1299 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1300 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1301
1302 //
1303 // Set the incoming port matching and the outgoing port output
1304 // actions for each flow entry.
1305 //
1306 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1307 // Set the incoming port matching
1308 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1309 flowEntry.setFlowEntryMatch(flowEntryMatch);
1310 flowEntryMatch.enableInPort(flowEntry.inPort());
1311
1312 // Set the outgoing port output action
1313 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1314 if (flowEntryActions == null) {
1315 flowEntryActions = new ArrayList<FlowEntryAction>();
1316 flowEntry.setFlowEntryActions(flowEntryActions);
1317 }
1318 FlowEntryAction flowEntryAction = new FlowEntryAction();
1319 flowEntryAction.setActionOutput(flowEntry.outPort());
1320 flowEntryActions.add(flowEntryAction);
1321 }
1322
1323 //
1324 // Remove the old Flow Entries, and add the new Flow Entries
1325 //
1326
1327 //
1328 // Remove the Flow Entries from the Network MAP
1329 //
1330 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1331 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1332 for (IFlowEntry flowEntryObj : flowEntries) {
1333 String dpidStr = flowEntryObj.getSwitchDpid();
1334 if (dpidStr == null)
1335 continue;
1336 Dpid dpid = new Dpid(dpidStr);
1337 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1338
1339 flowEntryObj.setUserState("FE_USER_DELETE");
1340 if (mySwitch == null) {
1341 //
1342 // Not my switch. Mark it for deletion in the Network MAP
1343 //
1344 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1345 continue;
1346 }
1347
1348 deleteFlowEntries.add(flowEntryObj);
1349
1350 //
1351 // Delete the flow entry from the switch
1352 //
1353 // flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1354 installFlowEntry(mySwitch, flowObj, flowEntryObj);
1355 // flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1356 }
1357 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
1358 flowObj.removeFlowEntry(flowEntryObj);
1359 conn.utils().removeFlowEntry(conn, flowEntryObj);
1360 }
1361
1362 //
1363 // Install the new shortest path into the Network MAP and the switches.
1364 //
1365 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1366 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1367 IFlowEntry flowEntryObj = addFlowEntry(flowObj, flowEntry);
1368 if (flowEntryObj == null) {
1369 //
1370 // TODO: Remove the "new Object[] wrapper in the statement
1371 // below after the SLF4J logger is upgraded to
1372 // Version 1.7.5
1373 //
1374 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1375 new Object[] {
1376 flowEntry.dpid(),
1377 newDataPath.srcPort(),
1378 newDataPath.dstPort()
1379 });
1380 continue;
1381 }
1382
1383 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1384 if (mySwitch == null) {
1385 // Not my switch: just add to the Network MAP
1386 continue;
1387 }
1388
1389 // Install the Flow Entry into the switch
1390 if (installFlowEntry(mySwitch, flowObj, flowEntryObj)) {
1391 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1392 }
1393 }
1394
1395 //
1396 // Set the Data Path Summary
1397 //
1398 String dataPathSummaryStr = newDataPath.dataPathSummary();
1399 flowObj.setDataPathSummary(dataPathSummaryStr);
1400
1401 return true;
1402 }
1403
1404 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001405 * Reconcile all flows in a set.
1406 *
1407 * @param flowObjSet the set of flows that need to be reconciliated.
1408 */
1409 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1410 if (! flowObjSet.iterator().hasNext())
1411 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001412 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001413 }
1414
1415 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001416 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001417 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001418 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001419 * @param flowObj the flow path object for the flow entry to install.
1420 * @param flowEntryObj the flow entry object to install.
1421 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001422 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001423 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1424 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001425 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1426 if (flowEntryIdStr == null)
1427 return false;
1428 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001429 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001430 if (userState == null)
1431 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001432
1433 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001434 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001435 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001436 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1437 .getMessage(OFType.FLOW_MOD);
1438 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001439
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001440 short flowModCommand = OFFlowMod.OFPFC_ADD;
1441 if (userState.equals("FE_USER_ADD")) {
1442 flowModCommand = OFFlowMod.OFPFC_ADD;
1443 } else if (userState.equals("FE_USER_MODIFY")) {
1444 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1445 } else if (userState.equals("FE_USER_DELETE")) {
1446 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1447 } else {
1448 // Unknown user state. Ignore the entry
1449 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1450 flowEntryId.toString(), userState);
1451 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001452 }
1453
1454 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001455 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001456 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001457 // NOTE: The Flow matching conditions common for all Flow Entries are
1458 // used ONLY if a Flow Entry does NOT have the corresponding matching
1459 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001460 //
1461 OFMatch match = new OFMatch();
1462 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001463
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001464 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001465 Short matchInPort = flowEntryObj.getMatchInPort();
1466 if (matchInPort != null) {
1467 match.setInputPort(matchInPort);
1468 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1469 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001470
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001471 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001472 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1473 if (matchEthernetFrameType == null)
1474 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1475 if (matchEthernetFrameType != null) {
1476 match.setDataLayerType(matchEthernetFrameType);
1477 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1478 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001479
1480 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001481 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1482 if (matchSrcIPv4Net == null)
1483 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1484 if (matchSrcIPv4Net != null) {
1485 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1486 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001487
1488 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001489 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1490 if (matchDstIPv4Net == null)
1491 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1492 if (matchDstIPv4Net != null) {
1493 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1494 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001495
1496 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001497 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1498 if (matchSrcMac == null)
1499 matchSrcMac = flowObj.getMatchSrcMac();
1500 if (matchSrcMac != null) {
1501 match.setDataLayerSource(matchSrcMac);
1502 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1503 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001504
1505 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001506 String matchDstMac = flowEntryObj.getMatchDstMac();
1507 if (matchDstMac == null)
1508 matchDstMac = flowObj.getMatchDstMac();
1509 if (matchDstMac != null) {
1510 match.setDataLayerDestination(matchDstMac);
1511 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1512 }
1513
1514 //
1515 // Fetch the actions
1516 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001517 // TODO: For now we support only the "OUTPUT" actions.
1518 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001519 List<OFAction> actions = new ArrayList<OFAction>();
1520 Short actionOutputPort = flowEntryObj.getActionOutput();
1521 if (actionOutputPort != null) {
1522 OFActionOutput action = new OFActionOutput();
1523 // XXX: The max length is hard-coded for now
1524 action.setMaxLength((short)0xffff);
1525 action.setPort(actionOutputPort);
1526 actions.add(action);
1527 }
1528
1529 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1530 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1531 .setPriority(PRIORITY_DEFAULT)
1532 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1533 .setCookie(cookie)
1534 .setCommand(flowModCommand)
1535 .setMatch(match)
1536 .setActions(actions)
1537 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1538 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1539 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1540 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1541 if (actionOutputPort != null)
1542 fm.setOutPort(actionOutputPort);
1543 }
1544
1545 //
1546 // TODO: Set the following flag
1547 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1548 // See method ForwardingBase::pushRoute()
1549 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001550
1551 //
1552 // Write the message to the switch
1553 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001554 log.debug("MEASUREMENT: Installing flow entry " + userState +
1555 " into switch DPID: " +
1556 mySwitch.getStringId() +
1557 " flowEntryId: " + flowEntryId.toString() +
1558 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1559 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1560 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001561 try {
1562 messageDamper.write(mySwitch, fm, null);
1563 mySwitch.flush();
1564 //
1565 // TODO: We should use the OpenFlow Barrier mechanism
1566 // to check for errors, and update the SwitchState
1567 // for a flow entry after the Barrier message is
1568 // is received.
1569 //
1570 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1571 } catch (IOException e) {
1572 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001573 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001574 }
1575
1576 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001577 }
1578
1579 /**
1580 * Install a Flow Entry on a switch.
1581 *
1582 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001583 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001584 * @param flowEntry the flow entry to install.
1585 * @return true on success, otherwise false.
1586 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001587 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1588 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001589 //
1590 // Create the OpenFlow Flow Modification Entry to push
1591 //
1592 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1593 .getMessage(OFType.FLOW_MOD);
1594 long cookie = flowEntry.flowEntryId().value();
1595
1596 short flowModCommand = OFFlowMod.OFPFC_ADD;
1597 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1598 flowModCommand = OFFlowMod.OFPFC_ADD;
1599 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1600 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1601 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1602 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1603 } else {
1604 // Unknown user state. Ignore the entry
1605 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1606 flowEntry.flowEntryId().toString(),
1607 flowEntry.flowEntryUserState());
1608 return false;
1609 }
1610
1611 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001612 // Fetch the match conditions.
1613 //
1614 // NOTE: The Flow matching conditions common for all Flow Entries are
1615 // used ONLY if a Flow Entry does NOT have the corresponding matching
1616 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001617 //
1618 OFMatch match = new OFMatch();
1619 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001620 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1621 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1622
1623 // Match the Incoming Port
1624 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001625 if (matchInPort != null) {
1626 match.setInputPort(matchInPort.value());
1627 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1628 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001629
1630 // Match the Ethernet Frame Type
1631 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1632 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1633 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1634 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001635 if (matchEthernetFrameType != null) {
1636 match.setDataLayerType(matchEthernetFrameType);
1637 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1638 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001639
1640 // Match the Source IPv4 Network prefix
1641 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1642 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1643 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1644 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001645 if (matchSrcIPv4Net != null) {
1646 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1647 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001648
1649 // Natch the Destination IPv4 Network prefix
1650 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1651 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1652 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1653 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001654 if (matchDstIPv4Net != null) {
1655 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1656 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001657
1658 // Match the Source MAC address
1659 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1660 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1661 matchSrcMac = flowPathMatch.srcMac();
1662 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001663 if (matchSrcMac != null) {
1664 match.setDataLayerSource(matchSrcMac.toString());
1665 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1666 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001667
1668 // Match the Destination MAC address
1669 MACAddress matchDstMac = flowEntryMatch.dstMac();
1670 if ((matchDstMac == null) && (flowPathMatch != null)) {
1671 matchDstMac = flowPathMatch.dstMac();
1672 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001673 if (matchDstMac != null) {
1674 match.setDataLayerDestination(matchDstMac.toString());
1675 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1676 }
1677
1678 //
1679 // Fetch the actions
1680 //
1681 // TODO: For now we support only the "OUTPUT" actions.
1682 //
1683 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1684 List<OFAction> actions = new ArrayList<OFAction>();
1685 ArrayList<FlowEntryAction> flowEntryActions =
1686 flowEntry.flowEntryActions();
1687 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1688 FlowEntryAction.ActionOutput actionOutput =
1689 flowEntryAction.actionOutput();
1690 if (actionOutput != null) {
1691 short actionOutputPort = actionOutput.port().value();
1692 OFActionOutput action = new OFActionOutput();
1693 // XXX: The max length is hard-coded for now
1694 action.setMaxLength((short)0xffff);
1695 action.setPort(actionOutputPort);
1696 actions.add(action);
1697 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1698 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1699 fm.setOutPort(actionOutputPort);
1700 }
1701 }
1702 }
1703
1704 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1705 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1706 .setPriority(PRIORITY_DEFAULT)
1707 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1708 .setCookie(cookie)
1709 .setCommand(flowModCommand)
1710 .setMatch(match)
1711 .setActions(actions)
1712 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1713
1714 //
1715 // TODO: Set the following flag
1716 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1717 // See method ForwardingBase::pushRoute()
1718 //
1719
1720 //
1721 // Write the message to the switch
1722 //
1723 try {
1724 messageDamper.write(mySwitch, fm, null);
1725 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001726 //
1727 // TODO: We should use the OpenFlow Barrier mechanism
1728 // to check for errors, and update the SwitchState
1729 // for a flow entry after the Barrier message is
1730 // is received.
1731 //
1732 // TODO: The FlowEntry Object in Titan should be set
1733 // to FE_SWITCH_UPDATED.
1734 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001735 } catch (IOException e) {
1736 log.error("Failure writing flow mod from network map", e);
1737 return false;
1738 }
1739 return true;
1740 }
1741
1742 /**
1743 * Remove a Flow Entry from a switch.
1744 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001745 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001746 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001747 * @param flowEntry the flow entry to remove.
1748 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001749 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001750 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1751 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001752 //
1753 // The installFlowEntry() method implements both installation
1754 // and removal of flow entries.
1755 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001756 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001757 }
1758
1759 /**
1760 * Install a Flow Entry on a remote controller.
1761 *
1762 * TODO: We need it now: Jono
1763 * - For now it will make a REST call to the remote controller.
1764 * - Internally, it needs to know the name of the remote controller.
1765 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001766 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001767 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001768 * @return true on success, otherwise false.
1769 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001770 public boolean installRemoteFlowEntry(FlowPath flowPath,
1771 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001772 // 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 return true;
1776 }
1777
1778 /**
1779 * Remove a flow entry on a remote controller.
1780 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001781 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001782 * @param flowEntry the flow entry to remove.
1783 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001784 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001785 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1786 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001787 //
1788 // The installRemoteFlowEntry() method implements both installation
1789 // and removal of flow entries.
1790 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001791 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001792 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001793}