blob: ab60e6876490139c5d08438304608a969070d196 [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();
119 Map<Long, IFlowEntry> myFlowEntries =
120 new TreeMap<Long, IFlowEntry>();
121 LinkedList<IFlowEntry> deleteFlowEntries =
122 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700123
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 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000129 Iterable<IFlowEntry> allFlowEntries =
130 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700131 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700132 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000133 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700134 String userState = flowEntryObj.getUserState();
135 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000136 String dpidStr = flowEntryObj.getSwitchDpid();
137 if ((flowEntryIdStr == null) ||
138 (userState == null) ||
139 (switchState == null) ||
140 (dpidStr == null)) {
141 log.debug("IGNORING Flow Entry entry with null fields");
142 continue;
143 }
144 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
145 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800146
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000147 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
148 continue; // Ignore the entry: nothing to do
149
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800150 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000151 if (mySwitch == null)
152 continue; // Ignore the entry: not my switch
153
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700154 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700155 if (userState.equals("FE_USER_DELETE")) {
156 // An entry that needs to be deleted.
157 deleteFlowEntries.add(flowEntryObj);
158 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700159 }
160
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700161 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
162 myFlowEntries.size());
163
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700164 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700165 // Process my Flow Entries in the Flow Entry ID order
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700166 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700167 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700168 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700169 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700170 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700171 IFlowPath flowObj =
172 conn.utils().getFlowPathByFlowEntry(conn,
173 flowEntryObj);
174 if (flowObj == null)
175 continue; // Should NOT happen
176
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700177 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700178 // TODO: Commented-out for now
179 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700180 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700181 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700182 processed_measurement_flow = true;
183 }
184 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700185 */
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700186
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700187 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700188 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000189 if (mySwitch == null)
190 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700191 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800192 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000193
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700194 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
195 deleteFlowEntries.size());
196
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000197 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700198 // Delete all entries marked for deletion from the
199 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200 //
201 // TODO: We should use the OpenFlow Barrier mechanism
202 // to check for errors, and delete the Flow Entries after the
203 // Barrier message is received.
204 //
205 while (! deleteFlowEntries.isEmpty()) {
206 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
207 IFlowPath flowObj =
208 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
209 if (flowObj == null) {
210 log.debug("Did not find FlowPath to be deleted");
211 continue;
212 }
213 flowObj.removeFlowEntry(flowEntryObj);
214 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000215 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700216
217
218 //
219 // Fetch and recompute the Shortest Path for those
220 // Flow Paths this controller is responsible for.
221 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700222 topoRouteService.prepareShortestPathTopo();
223 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
224 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
225 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700226 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700227 if (flowPathObj == null)
228 continue;
229 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
230 if (dataPathSummaryStr == null)
231 continue; // Could be invalid entry?
232 if (dataPathSummaryStr.isEmpty())
233 continue; // No need to maintain this flow
234
235 // Fetch the fields needed to recompute the shortest path
236 String flowIdStr = flowPathObj.getFlowId();
237 String srcDpidStr = flowPathObj.getSrcSwitch();
238 Short srcPortShort = flowPathObj.getSrcPort();
239 String dstDpidStr = flowPathObj.getDstSwitch();
240 Short dstPortShort = flowPathObj.getDstPort();
241 if ((flowIdStr == null) ||
242 (srcDpidStr == null) ||
243 (srcPortShort == null) ||
244 (dstDpidStr == null) ||
245 (dstPortShort == null)) {
246 log.debug("IGNORING Flow Path entry with null fields");
247 continue;
248 }
249
250 FlowId flowId = new FlowId(flowIdStr);
251 Dpid srcDpid = new Dpid(srcDpidStr);
252 Port srcPort = new Port(srcPortShort);
253 Dpid dstDpid = new Dpid(dstDpidStr);
254 Port dstPort = new Port(dstPortShort);
255 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
256 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700257
258 //
259 // Use the source DPID as a heuristic to decide
260 // which controller is responsible for maintaining the
261 // shortest path.
262 // NOTE: This heuristic is error-prone: if the switch
263 // goes away and no controller is responsible for that
264 // switch, then the original Flow Path is not cleaned-up
265 //
266 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
267 if (mySwitch == null)
268 continue; // Ignore: not my responsibility
269
270 counterMyFlowPaths++;
271
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700272 //
273 // NOTE: Using here the regular getShortestPath() method
274 // won't work here, because that method calls internally
275 // "conn.endTx(Transaction.COMMIT)", and that will
276 // invalidate all handlers to the Titan database.
277 // If we want to experiment with calling here
278 // getShortestPath(), we need to refactor that code
279 // to avoid closing the transaction.
280 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700281 DataPath dataPath =
282 topoRouteService.getTopoShortestPath(srcSwitchPort,
283 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000284 if (dataPath == null) {
285 // We need the DataPath to compare the paths
286 dataPath = new DataPath();
287 dataPath.setSrcPort(srcSwitchPort);
288 dataPath.setDstPort(dstSwitchPort);
289 }
290
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291 String newDataPathSummaryStr = dataPath.dataPathSummary();
292 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
293 continue; // Nothing changed
294
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700295 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
296 flowId.toString());
297 flowObjSet.add(flowPathObj);
298 }
Pavlin Radoslavov53a3a8c2013-04-04 04:34:50 -0700299 log.debug("MEASUREMENT: Found {} Flows to reconcile",
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700300 flowObjSet.size());
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700301 reconcileFlows(flowObjSet);
302 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700303
304
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800305 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700306
307 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700308 long estimatedTime =
309 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700310 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
311 (double)estimatedTime / 1000000000 + " sec";
312 log.debug(logMsg);
313 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700314
315 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700316 double rate = 0.0;
317 if (estimatedTime > 0)
318 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
319 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
320 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
321 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
322 counterAllFlowPaths + " MyFlowPaths: " +
323 counterMyFlowPaths + " in " +
324 (double)estimatedTime / 1000000000 + " sec: " +
325 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700326 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800327 }
328 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700329
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700330 final ScheduledFuture<?> mapReaderHandle =
331 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800332
333 @Override
334 public void init(String conf) {
335 conn = GraphDBConnection.getInstance(conf);
336 }
337
338 public void finalize() {
339 close();
340 }
341
342 @Override
343 public void close() {
344 conn.close();
345 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800346
347 @Override
348 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
349 Collection<Class<? extends IFloodlightService>> l =
350 new ArrayList<Class<? extends IFloodlightService>>();
351 l.add(IFlowService.class);
352 return l;
353 }
354
355 @Override
356 public Map<Class<? extends IFloodlightService>, IFloodlightService>
357 getServiceImpls() {
358 Map<Class<? extends IFloodlightService>,
359 IFloodlightService> m =
360 new HashMap<Class<? extends IFloodlightService>,
361 IFloodlightService>();
362 m.put(IFlowService.class, this);
363 return m;
364 }
365
366 @Override
367 public Collection<Class<? extends IFloodlightService>>
368 getModuleDependencies() {
369 Collection<Class<? extends IFloodlightService>> l =
370 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800371 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700372 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800373 l.add(IRestApiService.class);
374 return l;
375 }
376
377 @Override
378 public void init(FloodlightModuleContext context)
379 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700380 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800381 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700382 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800383 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
385 EnumSet.of(OFType.FLOW_MOD),
386 OFMESSAGE_DAMPER_TIMEOUT);
387 // TODO: An ugly hack!
388 String conf = "/tmp/cassandra.titan";
389 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800390 }
391
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000392 private long getNextFlowEntryId() {
393 //
394 // Generate the next Flow Entry ID.
395 // NOTE: For now, the higher 32 bits are random, and
396 // the lower 32 bits are sequential.
397 // In the future, we need a better allocation mechanism.
398 //
399 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
400 nextFlowEntryIdPrefix = randomGenerator.nextInt();
401 nextFlowEntryIdSuffix = 0;
402 } else {
403 nextFlowEntryIdSuffix++;
404 }
405 long result = (long)nextFlowEntryIdPrefix << 32;
406 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
407 return result;
408 }
409
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800410 @Override
411 public void startUp(FloodlightModuleContext context) {
412 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700413
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000414 // Initialize the Flow Entry ID generator
415 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800416 }
417
418 /**
419 * Add a flow.
420 *
421 * Internally, ONOS will automatically register the installer for
422 * receiving Flow Path Notifications for that path.
423 *
424 * @param flowPath the Flow Path to install.
425 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700426 * @param dataPathSummaryStr the data path summary string if the added
427 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800428 * @return true on success, otherwise false.
429 */
430 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700431 public boolean addFlow(FlowPath flowPath, FlowId flowId,
432 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700433 /*
434 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700435 if (flowPath.flowId().value() == measurementFlowId) {
436 modifiedMeasurementFlowTime = System.nanoTime();
437 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700438 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439
440 IFlowPath flowObj = null;
441 try {
442 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
443 != null) {
444 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
445 flowPath.flowId().toString());
446 } else {
447 flowObj = conn.utils().newFlowPath(conn);
448 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
449 flowPath.flowId().toString());
450 }
451 } catch (Exception e) {
452 // TODO: handle exceptions
453 conn.endTx(Transaction.ROLLBACK);
454 log.error(":addFlow FlowId:{} failed",
455 flowPath.flowId().toString());
456 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700457 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000458 log.error(":addFlow FlowId:{} failed: Flow object not created",
459 flowPath.flowId().toString());
460 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800461 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700462 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800463
464 //
465 // Set the Flow key:
466 // - flowId
467 //
468 flowObj.setFlowId(flowPath.flowId().toString());
469 flowObj.setType("flow");
470
471 //
472 // Set the Flow attributes:
473 // - flowPath.installerId()
474 // - flowPath.dataPath().srcPort()
475 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700476 // - flowPath.matchEthernetFrameType()
477 // - flowPath.matchSrcIPv4Net()
478 // - flowPath.matchDstIPv4Net()
479 // - flowPath.matchSrcMac()
480 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800481 //
482 flowObj.setInstallerId(flowPath.installerId().toString());
483 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
484 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
485 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
486 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700487 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
488 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
489 }
490 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
491 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
492 }
493 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
494 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
495 }
496 if (flowPath.flowEntryMatch().matchSrcMac()) {
497 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
498 }
499 if (flowPath.flowEntryMatch().matchDstMac()) {
500 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
501 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800502
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700503 if (dataPathSummaryStr != null) {
504 flowObj.setDataPathSummary(dataPathSummaryStr);
505 } else {
506 flowObj.setDataPathSummary("");
507 }
508
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509 // Flow edges:
510 // HeadFE
511
512
513 //
514 // Flow Entries:
515 // flowPath.dataPath().flowEntries()
516 //
517 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700518 if (addFlowEntry(flowObj, flowEntry) != true) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000519 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800520 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700521 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800522 }
523 conn.endTx(Transaction.COMMIT);
524
525 //
526 // TODO: We need a proper Flow ID allocation mechanism.
527 //
528 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700529
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800530 return true;
531 }
532
533 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700534 * Add a flow entry to the Network MAP.
535 *
536 * @param flowObj the corresponding Flow Path object for the Flow Entry.
537 * @param flowEntry the Flow Entry to install.
538 * @return true on success, otherwise false.
539 */
540 private boolean addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
541 // Flow edges
542 // HeadFE (TODO)
543
544 //
545 // Assign the FlowEntry ID.
546 //
547 if ((flowEntry.flowEntryId() == null) ||
548 (flowEntry.flowEntryId().value() == 0)) {
549 long id = getNextFlowEntryId();
550 flowEntry.setFlowEntryId(new FlowEntryId(id));
551 }
552
553 IFlowEntry flowEntryObj = null;
554 boolean found = false;
555 try {
556 if ((flowEntryObj =
557 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
558 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
559 flowEntry.flowEntryId().toString());
560 found = true;
561 } else {
562 flowEntryObj = conn.utils().newFlowEntry(conn);
563 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
564 flowEntry.flowEntryId().toString());
565 }
566 } catch (Exception e) {
567 log.error(":addFlow FlowEntryId:{} failed",
568 flowEntry.flowEntryId().toString());
569 return false;
570 }
571 if (flowEntryObj == null) {
572 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
573 flowEntry.flowEntryId().toString());
574 return false;
575 }
576
577 //
578 // Set the Flow Entry key:
579 // - flowEntry.flowEntryId()
580 //
581 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
582 flowEntryObj.setType("flow_entry");
583
584 //
585 // Set the Flow Entry Edges and attributes:
586 // - Switch edge
587 // - InPort edge
588 // - OutPort edge
589 //
590 // - flowEntry.flowEntryMatch()
591 // - flowEntry.flowEntryActions()
592 // - flowEntry.dpid()
593 // - flowEntry.flowEntryUserState()
594 // - flowEntry.flowEntrySwitchState()
595 // - flowEntry.flowEntryErrorState()
596 // - flowEntry.matchInPort()
597 // - flowEntry.matchEthernetFrameType()
598 // - flowEntry.matchSrcIPv4Net()
599 // - flowEntry.matchDstIPv4Net()
600 // - flowEntry.matchSrcMac()
601 // - flowEntry.matchDstMac()
602 // - flowEntry.actionOutput()
603 //
604 ISwitchObject sw =
605 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
606 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
607 flowEntryObj.setSwitch(sw);
608 if (flowEntry.flowEntryMatch().matchInPort()) {
609 IPortObject inport =
610 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
611 flowEntry.flowEntryMatch().inPort().value());
612 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
613 flowEntryObj.setInPort(inport);
614 }
615 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
616 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
617 }
618 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
619 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
620 }
621 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
622 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
623 }
624 if (flowEntry.flowEntryMatch().matchSrcMac()) {
625 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
626 }
627 if (flowEntry.flowEntryMatch().matchDstMac()) {
628 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
629 }
630
631 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
632 if (fa.actionOutput() != null) {
633 IPortObject outport =
634 conn.utils().searchPort(conn,
635 flowEntry.dpid().toString(),
636 fa.actionOutput().port().value());
637 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
638 flowEntryObj.setOutPort(outport);
639 }
640 }
641 // TODO: Hacks with hard-coded state names!
642 if (found)
643 flowEntryObj.setUserState("FE_USER_MODIFY");
644 else
645 flowEntryObj.setUserState("FE_USER_ADD");
646 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
647 //
648 // TODO: Take care of the FlowEntryErrorState.
649 //
650
651 // Flow Entries edges:
652 // Flow
653 // NextFE (TODO)
654 if (! found) {
655 flowObj.addFlowEntry(flowEntryObj);
656 flowEntryObj.setFlow(flowObj);
657 }
658
659 return true;
660 }
661
662 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800663 * Delete a previously added flow.
664 *
665 * @param flowId the Flow ID of the flow to delete.
666 * @return true on success, otherwise false.
667 */
668 @Override
669 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700670 /*
671 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700672 if (flowId.value() == measurementFlowId) {
673 modifiedMeasurementFlowTime = System.nanoTime();
674 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700675 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700676
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800677 IFlowPath flowObj = null;
678 //
679 // We just mark the entries for deletion,
680 // and let the switches remove each individual entry after
681 // it has been removed from the switches.
682 //
683 try {
684 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
685 != null) {
686 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
687 flowId.toString());
688 } else {
689 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
690 flowId.toString());
691 }
692 } catch (Exception e) {
693 // TODO: handle exceptions
694 conn.endTx(Transaction.ROLLBACK);
695 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
696 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700697 if (flowObj == null) {
698 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800699 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700700 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800701
702 //
703 // Find and mark for deletion all Flow Entries
704 //
705 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
706 boolean empty = true; // TODO: an ugly hack
707 for (IFlowEntry flowEntryObj : flowEntries) {
708 empty = false;
709 // flowObj.removeFlowEntry(flowEntryObj);
710 // conn.utils().removeFlowEntry(conn, flowEntryObj);
711 flowEntryObj.setUserState("FE_USER_DELETE");
712 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
713 }
714 // Remove from the database empty flows
715 if (empty)
716 conn.utils().removeFlowPath(conn, flowObj);
717 conn.endTx(Transaction.COMMIT);
718
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800719 return true;
720 }
721
722 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700723 * Clear the state for a previously added flow.
724 *
725 * @param flowId the Flow ID of the flow to clear.
726 * @return true on success, otherwise false.
727 */
728 @Override
729 public boolean clearFlow(FlowId flowId) {
730 IFlowPath flowObj = null;
731 try {
732 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
733 != null) {
734 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
735 flowId.toString());
736 } else {
737 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
738 flowId.toString());
739 }
740 } catch (Exception e) {
741 // TODO: handle exceptions
742 conn.endTx(Transaction.ROLLBACK);
743 log.error(":clearFlow FlowId:{} failed", flowId.toString());
744 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700745 if (flowObj == null) {
746 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700747 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700748 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700749
750 //
751 // Remove all Flow Entries
752 //
753 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
754 for (IFlowEntry flowEntryObj : flowEntries) {
755 flowObj.removeFlowEntry(flowEntryObj);
756 conn.utils().removeFlowEntry(conn, flowEntryObj);
757 }
758 // Remove the Flow itself
759 conn.utils().removeFlowPath(conn, flowObj);
760 conn.endTx(Transaction.COMMIT);
761
762 return true;
763 }
764
765 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800766 * Get a previously added flow.
767 *
768 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800769 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800770 */
771 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800772 public FlowPath getFlow(FlowId flowId) {
773 IFlowPath flowObj = null;
774 try {
775 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
776 != null) {
777 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
778 flowId.toString());
779 } else {
780 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
781 flowId.toString());
782 }
783 } catch (Exception e) {
784 // TODO: handle exceptions
785 conn.endTx(Transaction.ROLLBACK);
786 log.error(":getFlow FlowId:{} failed", flowId.toString());
787 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700788 if (flowObj == null) {
789 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800790 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700791 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800792
793 //
794 // Extract the Flow state
795 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800796 FlowPath flowPath = extractFlowPath(flowObj);
797 conn.endTx(Transaction.COMMIT);
798
799 return flowPath;
800 }
801
802 /**
803 * Get all previously added flows by a specific installer for a given
804 * data path endpoints.
805 *
806 * @param installerId the Caller ID of the installer of the flow to get.
807 * @param dataPathEndpoints the data path endpoints of the flow to get.
808 * @return the Flow Paths if found, otherwise null.
809 */
810 @Override
811 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
812 DataPathEndpoints dataPathEndpoints) {
813 //
814 // TODO: The implementation below is not optimal:
815 // We fetch all flows, and then return only the subset that match
816 // the query conditions.
817 // We should use the appropriate Titan/Gremlin query to filter-out
818 // the flows as appropriate.
819 //
820 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700821 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800822
823 if (allFlows == null) {
824 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700825 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800826 }
827
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800828 for (FlowPath flow : allFlows) {
829 //
830 // TODO: String-based comparison is sub-optimal.
831 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800832 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800833 //
834 if (! flow.installerId().toString().equals(installerId.toString()))
835 continue;
836 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
837 continue;
838 }
839 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
840 continue;
841 }
842 flowPaths.add(flow);
843 }
844
845 if (flowPaths.isEmpty()) {
846 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800847 } else {
848 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
849 }
850
851 return flowPaths;
852 }
853
854 /**
855 * Get all installed flows by all installers for given data path endpoints.
856 *
857 * @param dataPathEndpoints the data path endpoints of the flows to get.
858 * @return the Flow Paths if found, otherwise null.
859 */
860 @Override
861 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
862 //
863 // TODO: The implementation below is not optimal:
864 // We fetch all flows, and then return only the subset that match
865 // the query conditions.
866 // We should use the appropriate Titan/Gremlin query to filter-out
867 // the flows as appropriate.
868 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700869 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
870 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800871
872 if (allFlows == null) {
873 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700874 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800875 }
876
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800877 for (FlowPath flow : allFlows) {
878 //
879 // TODO: String-based comparison is sub-optimal.
880 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800881 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800882 //
883 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
884 continue;
885 }
886 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
887 continue;
888 }
889 flowPaths.add(flow);
890 }
891
892 if (flowPaths.isEmpty()) {
893 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800894 } else {
895 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
896 }
897
898 return flowPaths;
899 }
900
901 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700902 * Get summary of all installed flows by all installers in a given range
903 *
904 * @param flowId the data path endpoints of the flows to get.
905 * @param maxFlows: the maximum number of flows to be returned
906 * @return the Flow Paths if found, otherwise null.
907 */
908 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700909 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700910
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700911 // TODO: The implementation below is not optimal:
912 // We fetch all flows, and then return only the subset that match
913 // the query conditions.
914 // We should use the appropriate Titan/Gremlin query to filter-out
915 // the flows as appropriate.
916 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700917 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700918
Jonathan Hart01f2d272013-04-04 20:03:46 -0700919 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
920
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700921 Collections.sort(flowPathsWithoutFlowEntries,
922 new Comparator<IFlowPath>(){
923 @Override
924 public int compare(IFlowPath first, IFlowPath second) {
925 // TODO Auto-generated method stub
926 long result = new FlowId(first.getFlowId()).value()
927 - new FlowId(second.getFlowId()).value();
928 if (result > 0) return 1;
929 else if (result < 0) return -1;
930 else return 0;
931 }
932 }
933 );
934
Jonathan Hart01f2d272013-04-04 20:03:46 -0700935 return flowPathsWithoutFlowEntries;
936
937 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700938 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -0700939
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700940 if (allFlows == null) {
941 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700942 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700943 }
944
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700945 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700946
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700947 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700948 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700949
Pavlin Radoslavov96b43422013-04-04 19:14:56 -0700950 // start from desired flowId
951 if (flow.flowId().value() < flowId.value()) {
952 continue;
953 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700954
955 // Summarize by making null flow entry fields that are not relevant to report
956 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
957 flowEntry.setFlowEntryActions(null);
958 flowEntry.setFlowEntryMatch(null);
959 }
960
961 flowPaths.add(flow);
962 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
963 break;
964 }
965 }
966
967 if (flowPaths.isEmpty()) {
968 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700969 } else {
970 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
971 }
972
973 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -0700974 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700975 }
976
977 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800978 * Get all installed flows by all installers.
979 *
980 * @return the Flow Paths if found, otherwise null.
981 */
982 @Override
983 public ArrayList<FlowPath> getAllFlows() {
984 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700985 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800986
987 try {
988 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
989 log.debug("Get all FlowPaths: found FlowPaths");
990 } else {
991 log.debug("Get all FlowPaths: no FlowPaths found");
992 }
993 } catch (Exception e) {
994 // TODO: handle exceptions
995 conn.endTx(Transaction.ROLLBACK);
996 log.error(":getAllFlowPaths failed");
997 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700998 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
999 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001000 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001001 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001002
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001003 for (IFlowPath flowObj : flowPathsObj) {
1004 //
1005 // Extract the Flow state
1006 //
1007 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001008 if (flowPath != null)
1009 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001010 }
1011
1012 conn.endTx(Transaction.COMMIT);
1013
1014 return flowPaths;
1015 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001016
1017 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1018 Iterable<IFlowPath> flowPathsObj = null;
1019 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1020 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1021
1022 try {
1023 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1024 log.debug("Get all FlowPaths: found FlowPaths");
1025 } else {
1026 log.debug("Get all FlowPaths: no FlowPaths found");
1027 }
1028 } catch (Exception e) {
1029 // TODO: handle exceptions
1030 conn.endTx(Transaction.ROLLBACK);
1031 log.error(":getAllFlowPaths failed");
1032 }
1033 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1034 return new ArrayList<IFlowPath>(); // No Flows found
1035 }
1036
1037 for (IFlowPath flowObj : flowPathsObj){
1038 flowPathsObjArray.add(flowObj);
1039 }
1040 /*
1041 for (IFlowPath flowObj : flowPathsObj) {
1042 //
1043 // Extract the Flow state
1044 //
1045 FlowPath flowPath = extractFlowPath(flowObj);
1046 if (flowPath != null)
1047 flowPaths.add(flowPath);
1048 }
1049 */
1050
1051 //conn.endTx(Transaction.COMMIT);
1052
1053 return flowPathsObjArray;
1054 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001055
1056 /**
1057 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1058 *
1059 * @param flowObj the object to extract the Flow Path State from.
1060 * @return the extracted Flow Path State.
1061 */
1062 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001063 //
1064 // Extract the Flow state
1065 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001066 String flowIdStr = flowObj.getFlowId();
1067 String installerIdStr = flowObj.getInstallerId();
1068 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001069 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001070 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001071 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001072
1073 if ((flowIdStr == null) ||
1074 (installerIdStr == null) ||
1075 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001076 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001077 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001078 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001079 // TODO: A work-around, becauuse of some bogus database objects
1080 return null;
1081 }
1082
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001083 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001084 flowPath.setFlowId(new FlowId(flowIdStr));
1085 flowPath.setInstallerId(new CallerId(installerIdStr));
1086 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001087 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001088 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001089 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001090 //
1091 // Extract the match conditions common for all Flow Entries
1092 //
1093 {
1094 FlowEntryMatch match = new FlowEntryMatch();
1095 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1096 if (matchEthernetFrameType != null)
1097 match.enableEthernetFrameType(matchEthernetFrameType);
1098 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1099 if (matchSrcIPv4Net != null)
1100 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1101 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1102 if (matchDstIPv4Net != null)
1103 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1104 String matchSrcMac = flowObj.getMatchSrcMac();
1105 if (matchSrcMac != null)
1106 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1107 String matchDstMac = flowObj.getMatchDstMac();
1108 if (matchDstMac != null)
1109 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1110 flowPath.setFlowEntryMatch(match);
1111 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001112
1113 //
1114 // Extract all Flow Entries
1115 //
1116 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1117 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001118 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1119 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001120 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001121 flowPath.dataPath().flowEntries().add(flowEntry);
1122 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001123
1124 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001125 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001126
1127 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001128 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1129 *
1130 * @param flowEntryObj the object to extract the Flow Entry State from.
1131 * @return the extracted Flow Entry State.
1132 */
1133 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1134 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1135 String switchDpidStr = flowEntryObj.getSwitchDpid();
1136 String userState = flowEntryObj.getUserState();
1137 String switchState = flowEntryObj.getSwitchState();
1138
1139 if ((flowEntryIdStr == null) ||
1140 (switchDpidStr == null) ||
1141 (userState == null) ||
1142 (switchState == null)) {
1143 // TODO: A work-around, becauuse of some bogus database objects
1144 return null;
1145 }
1146
1147 FlowEntry flowEntry = new FlowEntry();
1148 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1149 flowEntry.setDpid(new Dpid(switchDpidStr));
1150
1151 //
1152 // Extract the match conditions
1153 //
1154 FlowEntryMatch match = new FlowEntryMatch();
1155 Short matchInPort = flowEntryObj.getMatchInPort();
1156 if (matchInPort != null)
1157 match.enableInPort(new Port(matchInPort));
1158 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1159 if (matchEthernetFrameType != null)
1160 match.enableEthernetFrameType(matchEthernetFrameType);
1161 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1162 if (matchSrcIPv4Net != null)
1163 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1164 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1165 if (matchDstIPv4Net != null)
1166 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1167 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1168 if (matchSrcMac != null)
1169 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1170 String matchDstMac = flowEntryObj.getMatchDstMac();
1171 if (matchDstMac != null)
1172 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1173 flowEntry.setFlowEntryMatch(match);
1174
1175 //
1176 // Extract the actions
1177 //
1178 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1179 Short actionOutputPort = flowEntryObj.getActionOutput();
1180 if (actionOutputPort != null) {
1181 FlowEntryAction action = new FlowEntryAction();
1182 action.setActionOutput(new Port(actionOutputPort));
1183 actions.add(action);
1184 }
1185 flowEntry.setFlowEntryActions(actions);
1186 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1187 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1188 //
1189 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1190 // and FlowEntryErrorState.
1191 //
1192 return flowEntry;
1193 }
1194
1195 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001196 * Add and maintain a shortest-path flow.
1197 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001198 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001199 *
1200 * @param flowPath the Flow Path with the endpoints and the match
1201 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001202 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001203 */
1204 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001205 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001206 String dataPathSummaryStr = null;
1207
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001208 //
1209 // Do the shortest path computation
1210 //
1211 DataPath dataPath =
1212 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1213 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001214 if (dataPath == null) {
1215 // We need the DataPath to populate the Network MAP
1216 dataPath = new DataPath();
1217 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1218 dataPath.setDstPort(flowPath.dataPath().dstPort());
1219 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001220
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001221 // Compute the Data Path summary
1222 dataPathSummaryStr = dataPath.dataPathSummary();
1223
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001224 //
1225 // Set the incoming port matching and the outgoing port output
1226 // actions for each flow entry.
1227 //
1228 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1229 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001230 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001231 flowEntry.setFlowEntryMatch(flowEntryMatch);
1232 flowEntryMatch.enableInPort(flowEntry.inPort());
1233
1234 // Set the outgoing port output action
1235 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1236 if (flowEntryActions == null) {
1237 flowEntryActions = new ArrayList<FlowEntryAction>();
1238 flowEntry.setFlowEntryActions(flowEntryActions);
1239 }
1240 FlowEntryAction flowEntryAction = new FlowEntryAction();
1241 flowEntryAction.setActionOutput(flowEntry.outPort());
1242 flowEntryActions.add(flowEntryAction);
1243 }
1244
1245 //
1246 // Prepare the computed Flow Path
1247 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001248 FlowPath computedFlowPath = new FlowPath();
1249 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1250 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1251 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001252 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001253
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001254 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001255 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001256 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001257
1258 // TODO: Mark the flow for maintenance purpose
1259
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001260 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001261 }
1262
1263 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001264 * Reconcile all flows in a set.
1265 *
1266 * @param flowObjSet the set of flows that need to be reconciliated.
1267 */
1268 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1269 if (! flowObjSet.iterator().hasNext())
1270 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001271
1272 //
1273 // Remove the old Flow Entries, and add the new Flow Entries
1274 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001275
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001276 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001277 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001278 for (IFlowPath flowObj : flowObjSet) {
1279 FlowPath flowPath = extractFlowPath(flowObj);
1280 if (flowPath == null)
1281 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001282 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001283
1284 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001285 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001286 //
1287 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001288 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001289 for (IFlowEntry flowEntryObj : flowEntries) {
1290 String dpidStr = flowEntryObj.getSwitchDpid();
1291 if (dpidStr == null)
1292 continue;
1293 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001294 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001295 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1296 if (mySwitch == null)
1297 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001298 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001299 deleteFlowEntries.add(flowEntryObj);
1300 }
1301 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001302 flowObj.removeFlowEntry(flowEntryObj);
1303 conn.utils().removeFlowEntry(conn, flowEntryObj);
1304 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001305 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001306
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001307 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001308 //
1309 // Delete the flow entries from the switches
1310 //
1311 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1312 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001313 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1314 if (mySwitch == null) {
1315 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001316 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001317 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001318 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001319 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001320 }
1321
1322 //
1323 // Calculate the new shortest path and install it in the
1324 // Network MAP.
1325 //
1326 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1327 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001328 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001329 flowPath.dataPath().srcPort().toString(),
1330 flowPath.dataPath().dstPort().toString());
1331 continue;
1332 }
1333
1334 //
1335 // Add the flow entries to the switches
1336 //
1337 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1338 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001339 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1340 if (mySwitch == null) {
1341 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001342 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001343 continue;
1344 }
1345
1346 IFlowEntry flowEntryObj =
1347 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1348 if (flowEntryObj == null) {
1349 //
1350 // TODO: Remove the "new Object[] wrapper in the statement
1351 // below after the SLF4J logger is upgraded to
1352 // Version 1.7.5
1353 //
1354 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1355 new Object[] {
1356 flowEntry.dpid(),
1357 flowPath.dataPath().srcPort(),
1358 flowPath.dataPath().dstPort()
1359 });
1360 continue;
1361 }
1362 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001363 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001364 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1365 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001366 }
1367 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001368 }
1369
1370 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001371 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001372 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001373 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001374 * @param flowObj the flow path object for the flow entry to install.
1375 * @param flowEntryObj the flow entry object to install.
1376 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001377 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001378 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1379 IFlowEntry flowEntryObj) {
1380 FlowEntryId flowEntryId =
1381 new FlowEntryId(flowEntryObj.getFlowEntryId());
1382 String userState = flowEntryObj.getUserState();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001383
1384 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001385 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001386 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001387 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1388 .getMessage(OFType.FLOW_MOD);
1389 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001390
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001391 short flowModCommand = OFFlowMod.OFPFC_ADD;
1392 if (userState.equals("FE_USER_ADD")) {
1393 flowModCommand = OFFlowMod.OFPFC_ADD;
1394 } else if (userState.equals("FE_USER_MODIFY")) {
1395 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1396 } else if (userState.equals("FE_USER_DELETE")) {
1397 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1398 } else {
1399 // Unknown user state. Ignore the entry
1400 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1401 flowEntryId.toString(), userState);
1402 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001403 }
1404
1405 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001406 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001407 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001408 // NOTE: The Flow matching conditions common for all Flow Entries are
1409 // used ONLY if a Flow Entry does NOT have the corresponding matching
1410 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001411 //
1412 OFMatch match = new OFMatch();
1413 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001414
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001415 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001416 Short matchInPort = flowEntryObj.getMatchInPort();
1417 if (matchInPort != null) {
1418 match.setInputPort(matchInPort);
1419 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1420 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001421
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001422 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001423 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1424 if (matchEthernetFrameType == null)
1425 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1426 if (matchEthernetFrameType != null) {
1427 match.setDataLayerType(matchEthernetFrameType);
1428 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1429 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001430
1431 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001432 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1433 if (matchSrcIPv4Net == null)
1434 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1435 if (matchSrcIPv4Net != null) {
1436 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1437 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001438
1439 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001440 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1441 if (matchDstIPv4Net == null)
1442 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1443 if (matchDstIPv4Net != null) {
1444 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1445 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001446
1447 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001448 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1449 if (matchSrcMac == null)
1450 matchSrcMac = flowObj.getMatchSrcMac();
1451 if (matchSrcMac != null) {
1452 match.setDataLayerSource(matchSrcMac);
1453 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1454 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001455
1456 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001457 String matchDstMac = flowEntryObj.getMatchDstMac();
1458 if (matchDstMac == null)
1459 matchDstMac = flowObj.getMatchDstMac();
1460 if (matchDstMac != null) {
1461 match.setDataLayerDestination(matchDstMac);
1462 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1463 }
1464
1465 //
1466 // Fetch the actions
1467 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001468 // TODO: For now we support only the "OUTPUT" actions.
1469 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001470 List<OFAction> actions = new ArrayList<OFAction>();
1471 Short actionOutputPort = flowEntryObj.getActionOutput();
1472 if (actionOutputPort != null) {
1473 OFActionOutput action = new OFActionOutput();
1474 // XXX: The max length is hard-coded for now
1475 action.setMaxLength((short)0xffff);
1476 action.setPort(actionOutputPort);
1477 actions.add(action);
1478 }
1479
1480 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1481 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1482 .setPriority(PRIORITY_DEFAULT)
1483 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1484 .setCookie(cookie)
1485 .setCommand(flowModCommand)
1486 .setMatch(match)
1487 .setActions(actions)
1488 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1489 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1490 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1491 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1492 if (actionOutputPort != null)
1493 fm.setOutPort(actionOutputPort);
1494 }
1495
1496 //
1497 // TODO: Set the following flag
1498 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1499 // See method ForwardingBase::pushRoute()
1500 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001501
1502 //
1503 // Write the message to the switch
1504 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001505 try {
1506 messageDamper.write(mySwitch, fm, null);
1507 mySwitch.flush();
1508 //
1509 // TODO: We should use the OpenFlow Barrier mechanism
1510 // to check for errors, and update the SwitchState
1511 // for a flow entry after the Barrier message is
1512 // is received.
1513 //
1514 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1515 } catch (IOException e) {
1516 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001517 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001518 }
1519
1520 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001521 }
1522
1523 /**
1524 * Install a Flow Entry on a switch.
1525 *
1526 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001527 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001528 * @param flowEntry the flow entry to install.
1529 * @return true on success, otherwise false.
1530 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001531 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1532 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001533 //
1534 // Create the OpenFlow Flow Modification Entry to push
1535 //
1536 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1537 .getMessage(OFType.FLOW_MOD);
1538 long cookie = flowEntry.flowEntryId().value();
1539
1540 short flowModCommand = OFFlowMod.OFPFC_ADD;
1541 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1542 flowModCommand = OFFlowMod.OFPFC_ADD;
1543 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1544 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1545 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1546 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1547 } else {
1548 // Unknown user state. Ignore the entry
1549 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1550 flowEntry.flowEntryId().toString(),
1551 flowEntry.flowEntryUserState());
1552 return false;
1553 }
1554
1555 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001556 // Fetch the match conditions.
1557 //
1558 // NOTE: The Flow matching conditions common for all Flow Entries are
1559 // used ONLY if a Flow Entry does NOT have the corresponding matching
1560 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001561 //
1562 OFMatch match = new OFMatch();
1563 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001564 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1565 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1566
1567 // Match the Incoming Port
1568 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001569 if (matchInPort != null) {
1570 match.setInputPort(matchInPort.value());
1571 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1572 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001573
1574 // Match the Ethernet Frame Type
1575 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1576 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1577 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1578 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001579 if (matchEthernetFrameType != null) {
1580 match.setDataLayerType(matchEthernetFrameType);
1581 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1582 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001583
1584 // Match the Source IPv4 Network prefix
1585 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1586 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1587 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1588 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001589 if (matchSrcIPv4Net != null) {
1590 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1591 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001592
1593 // Natch the Destination IPv4 Network prefix
1594 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1595 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1596 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1597 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001598 if (matchDstIPv4Net != null) {
1599 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1600 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001601
1602 // Match the Source MAC address
1603 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1604 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1605 matchSrcMac = flowPathMatch.srcMac();
1606 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001607 if (matchSrcMac != null) {
1608 match.setDataLayerSource(matchSrcMac.toString());
1609 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1610 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001611
1612 // Match the Destination MAC address
1613 MACAddress matchDstMac = flowEntryMatch.dstMac();
1614 if ((matchDstMac == null) && (flowPathMatch != null)) {
1615 matchDstMac = flowPathMatch.dstMac();
1616 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001617 if (matchDstMac != null) {
1618 match.setDataLayerDestination(matchDstMac.toString());
1619 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1620 }
1621
1622 //
1623 // Fetch the actions
1624 //
1625 // TODO: For now we support only the "OUTPUT" actions.
1626 //
1627 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1628 List<OFAction> actions = new ArrayList<OFAction>();
1629 ArrayList<FlowEntryAction> flowEntryActions =
1630 flowEntry.flowEntryActions();
1631 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1632 FlowEntryAction.ActionOutput actionOutput =
1633 flowEntryAction.actionOutput();
1634 if (actionOutput != null) {
1635 short actionOutputPort = actionOutput.port().value();
1636 OFActionOutput action = new OFActionOutput();
1637 // XXX: The max length is hard-coded for now
1638 action.setMaxLength((short)0xffff);
1639 action.setPort(actionOutputPort);
1640 actions.add(action);
1641 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1642 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1643 fm.setOutPort(actionOutputPort);
1644 }
1645 }
1646 }
1647
1648 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1649 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1650 .setPriority(PRIORITY_DEFAULT)
1651 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1652 .setCookie(cookie)
1653 .setCommand(flowModCommand)
1654 .setMatch(match)
1655 .setActions(actions)
1656 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1657
1658 //
1659 // TODO: Set the following flag
1660 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1661 // See method ForwardingBase::pushRoute()
1662 //
1663
1664 //
1665 // Write the message to the switch
1666 //
1667 try {
1668 messageDamper.write(mySwitch, fm, null);
1669 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001670 //
1671 // TODO: We should use the OpenFlow Barrier mechanism
1672 // to check for errors, and update the SwitchState
1673 // for a flow entry after the Barrier message is
1674 // is received.
1675 //
1676 // TODO: The FlowEntry Object in Titan should be set
1677 // to FE_SWITCH_UPDATED.
1678 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001679 } catch (IOException e) {
1680 log.error("Failure writing flow mod from network map", e);
1681 return false;
1682 }
1683 return true;
1684 }
1685
1686 /**
1687 * Remove a Flow Entry from a switch.
1688 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001689 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001690 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001691 * @param flowEntry the flow entry to remove.
1692 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001693 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001694 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1695 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001696 //
1697 // The installFlowEntry() method implements both installation
1698 // and removal of flow entries.
1699 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001700 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001701 }
1702
1703 /**
1704 * Install a Flow Entry on a remote controller.
1705 *
1706 * TODO: We need it now: Jono
1707 * - For now it will make a REST call to the remote controller.
1708 * - Internally, it needs to know the name of the remote controller.
1709 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001710 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001711 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001712 * @return true on success, otherwise false.
1713 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001714 public boolean installRemoteFlowEntry(FlowPath flowPath,
1715 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001716 // TODO: We need it now: Jono
1717 // - For now it will make a REST call to the remote controller.
1718 // - Internally, it needs to know the name of the remote controller.
1719 return true;
1720 }
1721
1722 /**
1723 * Remove a flow entry on a remote controller.
1724 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001725 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001726 * @param flowEntry the flow entry to remove.
1727 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001728 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001729 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1730 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001731 //
1732 // The installRemoteFlowEntry() method implements both installation
1733 // and removal of flow entries.
1734 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001735 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001736 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001737}