blob: 03f4ce719d611946e31d81e00ecef47d1a371e89 [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 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 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700129 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000130 Iterable<IFlowEntry> allFlowEntries =
131 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700132 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700133 counterAllFlowEntries++;
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700134 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000135 if ((switchState == null) ||
136 (! switchState.equals("FE_SWITCH_NOT_UPDATED"))) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137 continue; // Ignore the entry: nothing to do
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000138 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000139
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000140 String dpidStr = flowEntryObj.getSwitchDpid();
141 if (dpidStr == null)
142 continue;
143 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800144 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000145 if (mySwitch == null)
146 continue; // Ignore the entry: not my switch
147
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700148 IFlowPath flowObj =
149 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
150 if (flowObj == null)
151 continue; // Should NOT happen
152 if (flowObj.getFlowId() == null)
153 continue; // Invalid entry
154
155 //
156 // NOTE: For now we process the DELETE before the ADD
157 // to cover the more common scenario.
158 // TODO: This is error prone and needs to be fixed!
159 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000160 String userState = flowEntryObj.getUserState();
161 if (userState == null)
162 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700163 if (userState.equals("FE_USER_DELETE")) {
164 // An entry that needs to be deleted.
165 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700166 installFlowEntry(mySwitch, flowObj, flowEntryObj);
167 } else {
168 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700169 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700170 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700171 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700172 // TODO: Commented-out for now
173 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700174 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700175 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700176 processed_measurement_flow = true;
177 }
178 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700179 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700180 }
181
182 /*
183 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
184 addFlowEntries.size() + deleteFlowEntries.size());
185 */
186
187 //
188 // Process the Flow Entries that need to be added
189 //
190 for (IFlowEntry flowEntryObj : addFlowEntries) {
191 IFlowPath flowObj =
192 conn.utils().getFlowPathByFlowEntry(conn,
193 flowEntryObj);
194 if (flowObj == null)
195 continue; // Should NOT happen
196 if (flowObj.getFlowId() == null)
197 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000201 if (mySwitch == null)
202 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700203 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800204 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000205
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700206 /*
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700207 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
208 deleteFlowEntries.size());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700209 */
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700210
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700212 // Delete all entries marked for deletion from the
213 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000214 //
215 // TODO: We should use the OpenFlow Barrier mechanism
216 // to check for errors, and delete the Flow Entries after the
217 // Barrier message is received.
218 //
219 while (! deleteFlowEntries.isEmpty()) {
220 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
221 IFlowPath flowObj =
222 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
223 if (flowObj == null) {
224 log.debug("Did not find FlowPath to be deleted");
225 continue;
226 }
227 flowObj.removeFlowEntry(flowEntryObj);
228 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000229 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700230
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700231 //
232 // Fetch and recompute the Shortest Path for those
233 // Flow Paths this controller is responsible for.
234 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700235 topoRouteService.prepareShortestPathTopo();
236 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700237 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700238 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700239 if (flowPathObj == null)
240 continue;
241 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
242 if (dataPathSummaryStr == null)
243 continue; // Could be invalid entry?
244 if (dataPathSummaryStr.isEmpty())
245 continue; // No need to maintain this flow
246
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700247 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000248 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700249 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700250 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700251 //
252 // Use the source DPID as a heuristic to decide
253 // which controller is responsible for maintaining the
254 // shortest path.
255 // NOTE: This heuristic is error-prone: if the switch
256 // goes away and no controller is responsible for that
257 // switch, then the original Flow Path is not cleaned-up
258 //
259 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
260 if (mySwitch == null)
261 continue; // Ignore: not my responsibility
262
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000263 // Fetch the fields needed to recompute the shortest path
264 Short srcPortShort = flowPathObj.getSrcPort();
265 String dstDpidStr = flowPathObj.getDstSwitch();
266 Short dstPortShort = flowPathObj.getDstPort();
267 if ((srcPortShort == null) ||
268 (dstDpidStr == null) ||
269 (dstPortShort == null)) {
270 continue;
271 }
272
273 Port srcPort = new Port(srcPortShort);
274 Dpid dstDpid = new Dpid(dstDpidStr);
275 Port dstPort = new Port(dstPortShort);
276 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
277 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
278
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700279 counterMyFlowPaths++;
280
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700281 //
282 // NOTE: Using here the regular getShortestPath() method
283 // won't work here, because that method calls internally
284 // "conn.endTx(Transaction.COMMIT)", and that will
285 // invalidate all handlers to the Titan database.
286 // If we want to experiment with calling here
287 // getShortestPath(), we need to refactor that code
288 // to avoid closing the transaction.
289 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700290 DataPath dataPath =
291 topoRouteService.getTopoShortestPath(srcSwitchPort,
292 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000293 if (dataPath == null) {
294 // We need the DataPath to compare the paths
295 dataPath = new DataPath();
296 dataPath.setSrcPort(srcSwitchPort);
297 dataPath.setDstPort(dstSwitchPort);
298 }
299
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700300 String newDataPathSummaryStr = dataPath.dataPathSummary();
301 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
302 continue; // Nothing changed
303
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700304 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700305 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700306 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800308 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700309
310 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700311 long estimatedTime =
312 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700313 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
314 (double)estimatedTime / 1000000000 + " sec";
315 log.debug(logMsg);
316 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700317
318 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700319 double rate = 0.0;
320 if (estimatedTime > 0)
321 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
322 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
323 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
324 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
325 counterAllFlowPaths + " MyFlowPaths: " +
326 counterMyFlowPaths + " in " +
327 (double)estimatedTime / 1000000000 + " sec: " +
328 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700329 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800330 }
331 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700332
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700333 final ScheduledFuture<?> mapReaderHandle =
334 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800335
336 @Override
337 public void init(String conf) {
338 conn = GraphDBConnection.getInstance(conf);
339 }
340
341 public void finalize() {
342 close();
343 }
344
345 @Override
346 public void close() {
347 conn.close();
348 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800349
350 @Override
351 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
352 Collection<Class<? extends IFloodlightService>> l =
353 new ArrayList<Class<? extends IFloodlightService>>();
354 l.add(IFlowService.class);
355 return l;
356 }
357
358 @Override
359 public Map<Class<? extends IFloodlightService>, IFloodlightService>
360 getServiceImpls() {
361 Map<Class<? extends IFloodlightService>,
362 IFloodlightService> m =
363 new HashMap<Class<? extends IFloodlightService>,
364 IFloodlightService>();
365 m.put(IFlowService.class, this);
366 return m;
367 }
368
369 @Override
370 public Collection<Class<? extends IFloodlightService>>
371 getModuleDependencies() {
372 Collection<Class<? extends IFloodlightService>> l =
373 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800374 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700375 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800376 l.add(IRestApiService.class);
377 return l;
378 }
379
380 @Override
381 public void init(FloodlightModuleContext context)
382 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700383 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700385 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800386 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800387 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
388 EnumSet.of(OFType.FLOW_MOD),
389 OFMESSAGE_DAMPER_TIMEOUT);
390 // TODO: An ugly hack!
391 String conf = "/tmp/cassandra.titan";
392 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800393 }
394
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000395 private long getNextFlowEntryId() {
396 //
397 // Generate the next Flow Entry ID.
398 // NOTE: For now, the higher 32 bits are random, and
399 // the lower 32 bits are sequential.
400 // In the future, we need a better allocation mechanism.
401 //
402 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
403 nextFlowEntryIdPrefix = randomGenerator.nextInt();
404 nextFlowEntryIdSuffix = 0;
405 } else {
406 nextFlowEntryIdSuffix++;
407 }
408 long result = (long)nextFlowEntryIdPrefix << 32;
409 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
410 return result;
411 }
412
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800413 @Override
414 public void startUp(FloodlightModuleContext context) {
415 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700416
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000417 // Initialize the Flow Entry ID generator
418 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800419 }
420
421 /**
422 * Add a flow.
423 *
424 * Internally, ONOS will automatically register the installer for
425 * receiving Flow Path Notifications for that path.
426 *
427 * @param flowPath the Flow Path to install.
428 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700429 * @param dataPathSummaryStr the data path summary string if the added
430 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800431 * @return true on success, otherwise false.
432 */
433 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700434 public boolean addFlow(FlowPath flowPath, FlowId flowId,
435 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700436 /*
437 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700438 if (flowPath.flowId().value() == measurementFlowId) {
439 modifiedMeasurementFlowTime = System.nanoTime();
440 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700441 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800442
443 IFlowPath flowObj = null;
444 try {
445 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
446 != null) {
447 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
448 flowPath.flowId().toString());
449 } else {
450 flowObj = conn.utils().newFlowPath(conn);
451 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
452 flowPath.flowId().toString());
453 }
454 } catch (Exception e) {
455 // TODO: handle exceptions
456 conn.endTx(Transaction.ROLLBACK);
457 log.error(":addFlow FlowId:{} failed",
458 flowPath.flowId().toString());
459 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700460 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000461 log.error(":addFlow FlowId:{} failed: Flow object not created",
462 flowPath.flowId().toString());
463 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800464 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700465 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800466
467 //
468 // Set the Flow key:
469 // - flowId
470 //
471 flowObj.setFlowId(flowPath.flowId().toString());
472 flowObj.setType("flow");
473
474 //
475 // Set the Flow attributes:
476 // - flowPath.installerId()
477 // - flowPath.dataPath().srcPort()
478 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700479 // - flowPath.matchEthernetFrameType()
480 // - flowPath.matchSrcIPv4Net()
481 // - flowPath.matchDstIPv4Net()
482 // - flowPath.matchSrcMac()
483 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800484 //
485 flowObj.setInstallerId(flowPath.installerId().toString());
486 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
487 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
488 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
489 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700490 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
491 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
492 }
493 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
494 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
495 }
496 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
497 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
498 }
499 if (flowPath.flowEntryMatch().matchSrcMac()) {
500 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
501 }
502 if (flowPath.flowEntryMatch().matchDstMac()) {
503 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
504 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800505
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700506 if (dataPathSummaryStr != null) {
507 flowObj.setDataPathSummary(dataPathSummaryStr);
508 } else {
509 flowObj.setDataPathSummary("");
510 }
511
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800512 // Flow edges:
513 // HeadFE
514
515
516 //
517 // Flow Entries:
518 // flowPath.dataPath().flowEntries()
519 //
520 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700521 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000522 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800523 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700524 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800525 }
526 conn.endTx(Transaction.COMMIT);
527
528 //
529 // TODO: We need a proper Flow ID allocation mechanism.
530 //
531 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700532
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800533 return true;
534 }
535
536 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700537 * Add a flow entry to the Network MAP.
538 *
539 * @param flowObj the corresponding Flow Path object for the Flow Entry.
540 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700541 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700542 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700543 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700544 // Flow edges
545 // HeadFE (TODO)
546
547 //
548 // Assign the FlowEntry ID.
549 //
550 if ((flowEntry.flowEntryId() == null) ||
551 (flowEntry.flowEntryId().value() == 0)) {
552 long id = getNextFlowEntryId();
553 flowEntry.setFlowEntryId(new FlowEntryId(id));
554 }
555
556 IFlowEntry flowEntryObj = null;
557 boolean found = false;
558 try {
559 if ((flowEntryObj =
560 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
561 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
562 flowEntry.flowEntryId().toString());
563 found = true;
564 } else {
565 flowEntryObj = conn.utils().newFlowEntry(conn);
566 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
567 flowEntry.flowEntryId().toString());
568 }
569 } catch (Exception e) {
570 log.error(":addFlow FlowEntryId:{} failed",
571 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700572 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700573 }
574 if (flowEntryObj == null) {
575 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
576 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700577 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700578 }
579
580 //
581 // Set the Flow Entry key:
582 // - flowEntry.flowEntryId()
583 //
584 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
585 flowEntryObj.setType("flow_entry");
586
587 //
588 // Set the Flow Entry Edges and attributes:
589 // - Switch edge
590 // - InPort edge
591 // - OutPort edge
592 //
593 // - flowEntry.flowEntryMatch()
594 // - flowEntry.flowEntryActions()
595 // - flowEntry.dpid()
596 // - flowEntry.flowEntryUserState()
597 // - flowEntry.flowEntrySwitchState()
598 // - flowEntry.flowEntryErrorState()
599 // - flowEntry.matchInPort()
600 // - flowEntry.matchEthernetFrameType()
601 // - flowEntry.matchSrcIPv4Net()
602 // - flowEntry.matchDstIPv4Net()
603 // - flowEntry.matchSrcMac()
604 // - flowEntry.matchDstMac()
605 // - flowEntry.actionOutput()
606 //
607 ISwitchObject sw =
608 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
609 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
610 flowEntryObj.setSwitch(sw);
611 if (flowEntry.flowEntryMatch().matchInPort()) {
612 IPortObject inport =
613 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
614 flowEntry.flowEntryMatch().inPort().value());
615 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
616 flowEntryObj.setInPort(inport);
617 }
618 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
619 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
620 }
621 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
622 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
623 }
624 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
625 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
626 }
627 if (flowEntry.flowEntryMatch().matchSrcMac()) {
628 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
629 }
630 if (flowEntry.flowEntryMatch().matchDstMac()) {
631 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
632 }
633
634 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
635 if (fa.actionOutput() != null) {
636 IPortObject outport =
637 conn.utils().searchPort(conn,
638 flowEntry.dpid().toString(),
639 fa.actionOutput().port().value());
640 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
641 flowEntryObj.setOutPort(outport);
642 }
643 }
644 // TODO: Hacks with hard-coded state names!
645 if (found)
646 flowEntryObj.setUserState("FE_USER_MODIFY");
647 else
648 flowEntryObj.setUserState("FE_USER_ADD");
649 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
650 //
651 // TODO: Take care of the FlowEntryErrorState.
652 //
653
654 // Flow Entries edges:
655 // Flow
656 // NextFE (TODO)
657 if (! found) {
658 flowObj.addFlowEntry(flowEntryObj);
659 flowEntryObj.setFlow(flowObj);
660 }
661
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700662 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700663 }
664
665 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800666 * Delete a previously added flow.
667 *
668 * @param flowId the Flow ID of the flow to delete.
669 * @return true on success, otherwise false.
670 */
671 @Override
672 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700673 /*
674 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700675 if (flowId.value() == measurementFlowId) {
676 modifiedMeasurementFlowTime = System.nanoTime();
677 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700678 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700679
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800680 IFlowPath flowObj = null;
681 //
682 // We just mark the entries for deletion,
683 // and let the switches remove each individual entry after
684 // it has been removed from the switches.
685 //
686 try {
687 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
688 != null) {
689 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
690 flowId.toString());
691 } else {
692 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
693 flowId.toString());
694 }
695 } catch (Exception e) {
696 // TODO: handle exceptions
697 conn.endTx(Transaction.ROLLBACK);
698 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
699 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700700 if (flowObj == null) {
701 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800702 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700703 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800704
705 //
706 // Find and mark for deletion all Flow Entries
707 //
708 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
709 boolean empty = true; // TODO: an ugly hack
710 for (IFlowEntry flowEntryObj : flowEntries) {
711 empty = false;
712 // flowObj.removeFlowEntry(flowEntryObj);
713 // conn.utils().removeFlowEntry(conn, flowEntryObj);
714 flowEntryObj.setUserState("FE_USER_DELETE");
715 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
716 }
717 // Remove from the database empty flows
718 if (empty)
719 conn.utils().removeFlowPath(conn, flowObj);
720 conn.endTx(Transaction.COMMIT);
721
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800722 return true;
723 }
724
725 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700726 * Clear the state for a previously added flow.
727 *
728 * @param flowId the Flow ID of the flow to clear.
729 * @return true on success, otherwise false.
730 */
731 @Override
732 public boolean clearFlow(FlowId flowId) {
733 IFlowPath flowObj = null;
734 try {
735 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
736 != null) {
737 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
738 flowId.toString());
739 } else {
740 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
741 flowId.toString());
742 }
743 } catch (Exception e) {
744 // TODO: handle exceptions
745 conn.endTx(Transaction.ROLLBACK);
746 log.error(":clearFlow FlowId:{} failed", flowId.toString());
747 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700748 if (flowObj == null) {
749 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700750 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700751 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700752
753 //
754 // Remove all Flow Entries
755 //
756 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
757 for (IFlowEntry flowEntryObj : flowEntries) {
758 flowObj.removeFlowEntry(flowEntryObj);
759 conn.utils().removeFlowEntry(conn, flowEntryObj);
760 }
761 // Remove the Flow itself
762 conn.utils().removeFlowPath(conn, flowObj);
763 conn.endTx(Transaction.COMMIT);
764
765 return true;
766 }
767
768 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800769 * Get a previously added flow.
770 *
771 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800772 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800773 */
774 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800775 public FlowPath getFlow(FlowId flowId) {
776 IFlowPath flowObj = null;
777 try {
778 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
779 != null) {
780 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
781 flowId.toString());
782 } else {
783 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
784 flowId.toString());
785 }
786 } catch (Exception e) {
787 // TODO: handle exceptions
788 conn.endTx(Transaction.ROLLBACK);
789 log.error(":getFlow FlowId:{} failed", flowId.toString());
790 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700791 if (flowObj == null) {
792 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800793 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700794 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800795
796 //
797 // Extract the Flow state
798 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800799 FlowPath flowPath = extractFlowPath(flowObj);
800 conn.endTx(Transaction.COMMIT);
801
802 return flowPath;
803 }
804
805 /**
806 * Get all previously added flows by a specific installer for a given
807 * data path endpoints.
808 *
809 * @param installerId the Caller ID of the installer of the flow to get.
810 * @param dataPathEndpoints the data path endpoints of the flow to get.
811 * @return the Flow Paths if found, otherwise null.
812 */
813 @Override
814 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
815 DataPathEndpoints dataPathEndpoints) {
816 //
817 // TODO: The implementation below is not optimal:
818 // We fetch all flows, and then return only the subset that match
819 // the query conditions.
820 // We should use the appropriate Titan/Gremlin query to filter-out
821 // the flows as appropriate.
822 //
823 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700824 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800825
826 if (allFlows == null) {
827 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700828 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800829 }
830
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800831 for (FlowPath flow : allFlows) {
832 //
833 // TODO: String-based comparison is sub-optimal.
834 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800835 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800836 //
837 if (! flow.installerId().toString().equals(installerId.toString()))
838 continue;
839 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
840 continue;
841 }
842 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
843 continue;
844 }
845 flowPaths.add(flow);
846 }
847
848 if (flowPaths.isEmpty()) {
849 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800850 } else {
851 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
852 }
853
854 return flowPaths;
855 }
856
857 /**
858 * Get all installed flows by all installers for given data path endpoints.
859 *
860 * @param dataPathEndpoints the data path endpoints of the flows to get.
861 * @return the Flow Paths if found, otherwise null.
862 */
863 @Override
864 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
865 //
866 // TODO: The implementation below is not optimal:
867 // We fetch all flows, and then return only the subset that match
868 // the query conditions.
869 // We should use the appropriate Titan/Gremlin query to filter-out
870 // the flows as appropriate.
871 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700872 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
873 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800874
875 if (allFlows == null) {
876 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700877 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800878 }
879
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800880 for (FlowPath flow : allFlows) {
881 //
882 // TODO: String-based comparison is sub-optimal.
883 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800884 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800885 //
886 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
887 continue;
888 }
889 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
890 continue;
891 }
892 flowPaths.add(flow);
893 }
894
895 if (flowPaths.isEmpty()) {
896 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800897 } else {
898 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
899 }
900
901 return flowPaths;
902 }
903
904 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700905 * Get summary of all installed flows by all installers in a given range
906 *
907 * @param flowId the data path endpoints of the flows to get.
908 * @param maxFlows: the maximum number of flows to be returned
909 * @return the Flow Paths if found, otherwise null.
910 */
911 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700912 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700913
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700914 // TODO: The implementation below is not optimal:
915 // We fetch all flows, and then return only the subset that match
916 // the query conditions.
917 // We should use the appropriate Titan/Gremlin query to filter-out
918 // the flows as appropriate.
919 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700920 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700921
Jonathan Hart01f2d272013-04-04 20:03:46 -0700922 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
923
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700924 Collections.sort(flowPathsWithoutFlowEntries,
925 new Comparator<IFlowPath>(){
926 @Override
927 public int compare(IFlowPath first, IFlowPath second) {
928 // TODO Auto-generated method stub
929 long result = new FlowId(first.getFlowId()).value()
930 - new FlowId(second.getFlowId()).value();
931 if (result > 0) return 1;
932 else if (result < 0) return -1;
933 else return 0;
934 }
935 }
936 );
937
Jonathan Hart01f2d272013-04-04 20:03:46 -0700938 return flowPathsWithoutFlowEntries;
939
940 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700941 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -0700942
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700943 if (allFlows == null) {
944 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700945 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700946 }
947
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700948 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700949
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700950 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700951 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700952
Pavlin Radoslavov96b43422013-04-04 19:14:56 -0700953 // start from desired flowId
954 if (flow.flowId().value() < flowId.value()) {
955 continue;
956 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700957
958 // Summarize by making null flow entry fields that are not relevant to report
959 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
960 flowEntry.setFlowEntryActions(null);
961 flowEntry.setFlowEntryMatch(null);
962 }
963
964 flowPaths.add(flow);
965 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
966 break;
967 }
968 }
969
970 if (flowPaths.isEmpty()) {
971 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700972 } else {
973 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
974 }
975
976 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -0700977 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700978 }
979
980 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800981 * Get all installed flows by all installers.
982 *
983 * @return the Flow Paths if found, otherwise null.
984 */
985 @Override
986 public ArrayList<FlowPath> getAllFlows() {
987 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700988 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800989
990 try {
991 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
992 log.debug("Get all FlowPaths: found FlowPaths");
993 } else {
994 log.debug("Get all FlowPaths: no FlowPaths found");
995 }
996 } catch (Exception e) {
997 // TODO: handle exceptions
998 conn.endTx(Transaction.ROLLBACK);
999 log.error(":getAllFlowPaths failed");
1000 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001001 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1002 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001003 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001004 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001005
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001006 for (IFlowPath flowObj : flowPathsObj) {
1007 //
1008 // Extract the Flow state
1009 //
1010 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001011 if (flowPath != null)
1012 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001013 }
1014
1015 conn.endTx(Transaction.COMMIT);
1016
1017 return flowPaths;
1018 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001019
1020 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1021 Iterable<IFlowPath> flowPathsObj = null;
1022 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1023 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1024
1025 try {
1026 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1027 log.debug("Get all FlowPaths: found FlowPaths");
1028 } else {
1029 log.debug("Get all FlowPaths: no FlowPaths found");
1030 }
1031 } catch (Exception e) {
1032 // TODO: handle exceptions
1033 conn.endTx(Transaction.ROLLBACK);
1034 log.error(":getAllFlowPaths failed");
1035 }
1036 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1037 return new ArrayList<IFlowPath>(); // No Flows found
1038 }
1039
1040 for (IFlowPath flowObj : flowPathsObj){
1041 flowPathsObjArray.add(flowObj);
1042 }
1043 /*
1044 for (IFlowPath flowObj : flowPathsObj) {
1045 //
1046 // Extract the Flow state
1047 //
1048 FlowPath flowPath = extractFlowPath(flowObj);
1049 if (flowPath != null)
1050 flowPaths.add(flowPath);
1051 }
1052 */
1053
1054 //conn.endTx(Transaction.COMMIT);
1055
1056 return flowPathsObjArray;
1057 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001058
1059 /**
1060 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1061 *
1062 * @param flowObj the object to extract the Flow Path State from.
1063 * @return the extracted Flow Path State.
1064 */
1065 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001066 //
1067 // Extract the Flow state
1068 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001069 String flowIdStr = flowObj.getFlowId();
1070 String installerIdStr = flowObj.getInstallerId();
1071 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001072 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001073 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001074 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001075
1076 if ((flowIdStr == null) ||
1077 (installerIdStr == null) ||
1078 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001079 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001080 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001081 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001082 // TODO: A work-around, becauuse of some bogus database objects
1083 return null;
1084 }
1085
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001086 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001087 flowPath.setFlowId(new FlowId(flowIdStr));
1088 flowPath.setInstallerId(new CallerId(installerIdStr));
1089 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001090 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001091 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001092 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001093 //
1094 // Extract the match conditions common for all Flow Entries
1095 //
1096 {
1097 FlowEntryMatch match = new FlowEntryMatch();
1098 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1099 if (matchEthernetFrameType != null)
1100 match.enableEthernetFrameType(matchEthernetFrameType);
1101 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1102 if (matchSrcIPv4Net != null)
1103 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1104 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1105 if (matchDstIPv4Net != null)
1106 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1107 String matchSrcMac = flowObj.getMatchSrcMac();
1108 if (matchSrcMac != null)
1109 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1110 String matchDstMac = flowObj.getMatchDstMac();
1111 if (matchDstMac != null)
1112 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1113 flowPath.setFlowEntryMatch(match);
1114 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001115
1116 //
1117 // Extract all Flow Entries
1118 //
1119 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1120 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001121 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1122 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001123 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001124 flowPath.dataPath().flowEntries().add(flowEntry);
1125 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001126
1127 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001128 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001129
1130 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001131 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1132 *
1133 * @param flowEntryObj the object to extract the Flow Entry State from.
1134 * @return the extracted Flow Entry State.
1135 */
1136 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1137 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1138 String switchDpidStr = flowEntryObj.getSwitchDpid();
1139 String userState = flowEntryObj.getUserState();
1140 String switchState = flowEntryObj.getSwitchState();
1141
1142 if ((flowEntryIdStr == null) ||
1143 (switchDpidStr == null) ||
1144 (userState == null) ||
1145 (switchState == null)) {
1146 // TODO: A work-around, becauuse of some bogus database objects
1147 return null;
1148 }
1149
1150 FlowEntry flowEntry = new FlowEntry();
1151 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1152 flowEntry.setDpid(new Dpid(switchDpidStr));
1153
1154 //
1155 // Extract the match conditions
1156 //
1157 FlowEntryMatch match = new FlowEntryMatch();
1158 Short matchInPort = flowEntryObj.getMatchInPort();
1159 if (matchInPort != null)
1160 match.enableInPort(new Port(matchInPort));
1161 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1162 if (matchEthernetFrameType != null)
1163 match.enableEthernetFrameType(matchEthernetFrameType);
1164 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1165 if (matchSrcIPv4Net != null)
1166 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1167 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1168 if (matchDstIPv4Net != null)
1169 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1170 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1171 if (matchSrcMac != null)
1172 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1173 String matchDstMac = flowEntryObj.getMatchDstMac();
1174 if (matchDstMac != null)
1175 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1176 flowEntry.setFlowEntryMatch(match);
1177
1178 //
1179 // Extract the actions
1180 //
1181 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1182 Short actionOutputPort = flowEntryObj.getActionOutput();
1183 if (actionOutputPort != null) {
1184 FlowEntryAction action = new FlowEntryAction();
1185 action.setActionOutput(new Port(actionOutputPort));
1186 actions.add(action);
1187 }
1188 flowEntry.setFlowEntryActions(actions);
1189 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1190 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1191 //
1192 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1193 // and FlowEntryErrorState.
1194 //
1195 return flowEntry;
1196 }
1197
1198 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001199 * Add and maintain a shortest-path flow.
1200 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001201 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001202 *
1203 * @param flowPath the Flow Path with the endpoints and the match
1204 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001205 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001206 */
1207 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001208 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001209 String dataPathSummaryStr = null;
1210
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001211 //
1212 // Do the shortest path computation
1213 //
1214 DataPath dataPath =
1215 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1216 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001217 if (dataPath == null) {
1218 // We need the DataPath to populate the Network MAP
1219 dataPath = new DataPath();
1220 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1221 dataPath.setDstPort(flowPath.dataPath().dstPort());
1222 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001223
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001224 // Compute the Data Path summary
1225 dataPathSummaryStr = dataPath.dataPathSummary();
1226
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001227 //
1228 // Set the incoming port matching and the outgoing port output
1229 // actions for each flow entry.
1230 //
1231 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1232 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001233 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001234 flowEntry.setFlowEntryMatch(flowEntryMatch);
1235 flowEntryMatch.enableInPort(flowEntry.inPort());
1236
1237 // Set the outgoing port output action
1238 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1239 if (flowEntryActions == null) {
1240 flowEntryActions = new ArrayList<FlowEntryAction>();
1241 flowEntry.setFlowEntryActions(flowEntryActions);
1242 }
1243 FlowEntryAction flowEntryAction = new FlowEntryAction();
1244 flowEntryAction.setActionOutput(flowEntry.outPort());
1245 flowEntryActions.add(flowEntryAction);
1246 }
1247
1248 //
1249 // Prepare the computed Flow Path
1250 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001251 FlowPath computedFlowPath = new FlowPath();
1252 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1253 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1254 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001255 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001256
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001257 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001258 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001259 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001260
1261 // TODO: Mark the flow for maintenance purpose
1262
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001263 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001264 }
1265
1266 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001267 * Reconcile a flow.
1268 *
1269 * @param flowObj the flow that needs to be reconciliated.
1270 * @param newDataPath the new data path to use.
1271 * @return true on success, otherwise false.
1272 */
1273 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1274 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1275
1276 //
1277 // Set the incoming port matching and the outgoing port output
1278 // actions for each flow entry.
1279 //
1280 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1281 // Set the incoming port matching
1282 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1283 flowEntry.setFlowEntryMatch(flowEntryMatch);
1284 flowEntryMatch.enableInPort(flowEntry.inPort());
1285
1286 // Set the outgoing port output action
1287 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1288 if (flowEntryActions == null) {
1289 flowEntryActions = new ArrayList<FlowEntryAction>();
1290 flowEntry.setFlowEntryActions(flowEntryActions);
1291 }
1292 FlowEntryAction flowEntryAction = new FlowEntryAction();
1293 flowEntryAction.setActionOutput(flowEntry.outPort());
1294 flowEntryActions.add(flowEntryAction);
1295 }
1296
1297 //
1298 // Remove the old Flow Entries, and add the new Flow Entries
1299 //
1300
1301 //
1302 // Remove the Flow Entries from the Network MAP
1303 //
1304 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1305 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1306 for (IFlowEntry flowEntryObj : flowEntries) {
1307 String dpidStr = flowEntryObj.getSwitchDpid();
1308 if (dpidStr == null)
1309 continue;
1310 Dpid dpid = new Dpid(dpidStr);
1311 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1312
1313 flowEntryObj.setUserState("FE_USER_DELETE");
1314 if (mySwitch == null) {
1315 //
1316 // Not my switch. Mark it for deletion in the Network MAP
1317 //
1318 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1319 continue;
1320 }
1321
1322 deleteFlowEntries.add(flowEntryObj);
1323
1324 //
1325 // Delete the flow entry from the switch
1326 //
1327 // flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1328 installFlowEntry(mySwitch, flowObj, flowEntryObj);
1329 // flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1330 }
1331 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
1332 flowObj.removeFlowEntry(flowEntryObj);
1333 conn.utils().removeFlowEntry(conn, flowEntryObj);
1334 }
1335
1336 //
1337 // Install the new shortest path into the Network MAP and the switches.
1338 //
1339 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1340 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1341 IFlowEntry flowEntryObj = addFlowEntry(flowObj, flowEntry);
1342 if (flowEntryObj == null) {
1343 //
1344 // TODO: Remove the "new Object[] wrapper in the statement
1345 // below after the SLF4J logger is upgraded to
1346 // Version 1.7.5
1347 //
1348 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1349 new Object[] {
1350 flowEntry.dpid(),
1351 newDataPath.srcPort(),
1352 newDataPath.dstPort()
1353 });
1354 continue;
1355 }
1356
1357 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1358 if (mySwitch == null) {
1359 // Not my switch: just add to the Network MAP
1360 continue;
1361 }
1362
1363 // Install the Flow Entry into the switch
1364 if (installFlowEntry(mySwitch, flowObj, flowEntryObj)) {
1365 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1366 }
1367 }
1368
1369 //
1370 // Set the Data Path Summary
1371 //
1372 String dataPathSummaryStr = newDataPath.dataPathSummary();
1373 flowObj.setDataPathSummary(dataPathSummaryStr);
1374
1375 return true;
1376 }
1377
1378 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001379 * Reconcile all flows in a set.
1380 *
1381 * @param flowObjSet the set of flows that need to be reconciliated.
1382 */
1383 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1384 if (! flowObjSet.iterator().hasNext())
1385 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001386 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001387 }
1388
1389 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001390 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001391 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001392 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001393 * @param flowObj the flow path object for the flow entry to install.
1394 * @param flowEntryObj the flow entry object to install.
1395 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001396 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001397 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1398 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001399 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1400 if (flowEntryIdStr == null)
1401 return false;
1402 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001403 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001404 if (userState == null)
1405 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001406
1407 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001408 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001409 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001410 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1411 .getMessage(OFType.FLOW_MOD);
1412 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001413
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001414 short flowModCommand = OFFlowMod.OFPFC_ADD;
1415 if (userState.equals("FE_USER_ADD")) {
1416 flowModCommand = OFFlowMod.OFPFC_ADD;
1417 } else if (userState.equals("FE_USER_MODIFY")) {
1418 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1419 } else if (userState.equals("FE_USER_DELETE")) {
1420 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1421 } else {
1422 // Unknown user state. Ignore the entry
1423 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1424 flowEntryId.toString(), userState);
1425 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001426 }
1427
1428 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001429 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001430 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001431 // NOTE: The Flow matching conditions common for all Flow Entries are
1432 // used ONLY if a Flow Entry does NOT have the corresponding matching
1433 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001434 //
1435 OFMatch match = new OFMatch();
1436 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001437
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001438 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001439 Short matchInPort = flowEntryObj.getMatchInPort();
1440 if (matchInPort != null) {
1441 match.setInputPort(matchInPort);
1442 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1443 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001444
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001445 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001446 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1447 if (matchEthernetFrameType == null)
1448 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1449 if (matchEthernetFrameType != null) {
1450 match.setDataLayerType(matchEthernetFrameType);
1451 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1452 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001453
1454 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001455 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1456 if (matchSrcIPv4Net == null)
1457 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1458 if (matchSrcIPv4Net != null) {
1459 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1460 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001461
1462 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001463 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1464 if (matchDstIPv4Net == null)
1465 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1466 if (matchDstIPv4Net != null) {
1467 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1468 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001469
1470 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001471 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1472 if (matchSrcMac == null)
1473 matchSrcMac = flowObj.getMatchSrcMac();
1474 if (matchSrcMac != null) {
1475 match.setDataLayerSource(matchSrcMac);
1476 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1477 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001478
1479 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001480 String matchDstMac = flowEntryObj.getMatchDstMac();
1481 if (matchDstMac == null)
1482 matchDstMac = flowObj.getMatchDstMac();
1483 if (matchDstMac != null) {
1484 match.setDataLayerDestination(matchDstMac);
1485 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1486 }
1487
1488 //
1489 // Fetch the actions
1490 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001491 // TODO: For now we support only the "OUTPUT" actions.
1492 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001493 List<OFAction> actions = new ArrayList<OFAction>();
1494 Short actionOutputPort = flowEntryObj.getActionOutput();
1495 if (actionOutputPort != null) {
1496 OFActionOutput action = new OFActionOutput();
1497 // XXX: The max length is hard-coded for now
1498 action.setMaxLength((short)0xffff);
1499 action.setPort(actionOutputPort);
1500 actions.add(action);
1501 }
1502
1503 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1504 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1505 .setPriority(PRIORITY_DEFAULT)
1506 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1507 .setCookie(cookie)
1508 .setCommand(flowModCommand)
1509 .setMatch(match)
1510 .setActions(actions)
1511 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1512 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1513 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1514 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1515 if (actionOutputPort != null)
1516 fm.setOutPort(actionOutputPort);
1517 }
1518
1519 //
1520 // TODO: Set the following flag
1521 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1522 // See method ForwardingBase::pushRoute()
1523 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001524
1525 //
1526 // Write the message to the switch
1527 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001528 log.debug("MEASUREMENT: Installing flow entry " + userState +
1529 " into switch DPID: " +
1530 mySwitch.getStringId() +
1531 " flowEntryId: " + flowEntryId.toString() +
1532 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1533 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1534 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001535 try {
1536 messageDamper.write(mySwitch, fm, null);
1537 mySwitch.flush();
1538 //
1539 // TODO: We should use the OpenFlow Barrier mechanism
1540 // to check for errors, and update the SwitchState
1541 // for a flow entry after the Barrier message is
1542 // is received.
1543 //
1544 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1545 } catch (IOException e) {
1546 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001547 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001548 }
1549
1550 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001551 }
1552
1553 /**
1554 * Install a Flow Entry on a switch.
1555 *
1556 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001557 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001558 * @param flowEntry the flow entry to install.
1559 * @return true on success, otherwise false.
1560 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001561 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1562 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001563 //
1564 // Create the OpenFlow Flow Modification Entry to push
1565 //
1566 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1567 .getMessage(OFType.FLOW_MOD);
1568 long cookie = flowEntry.flowEntryId().value();
1569
1570 short flowModCommand = OFFlowMod.OFPFC_ADD;
1571 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1572 flowModCommand = OFFlowMod.OFPFC_ADD;
1573 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1574 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1575 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1576 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1577 } else {
1578 // Unknown user state. Ignore the entry
1579 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1580 flowEntry.flowEntryId().toString(),
1581 flowEntry.flowEntryUserState());
1582 return false;
1583 }
1584
1585 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001586 // Fetch the match conditions.
1587 //
1588 // NOTE: The Flow matching conditions common for all Flow Entries are
1589 // used ONLY if a Flow Entry does NOT have the corresponding matching
1590 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001591 //
1592 OFMatch match = new OFMatch();
1593 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001594 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1595 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1596
1597 // Match the Incoming Port
1598 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001599 if (matchInPort != null) {
1600 match.setInputPort(matchInPort.value());
1601 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1602 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001603
1604 // Match the Ethernet Frame Type
1605 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1606 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1607 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1608 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001609 if (matchEthernetFrameType != null) {
1610 match.setDataLayerType(matchEthernetFrameType);
1611 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1612 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001613
1614 // Match the Source IPv4 Network prefix
1615 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1616 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1617 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1618 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001619 if (matchSrcIPv4Net != null) {
1620 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1621 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001622
1623 // Natch the Destination IPv4 Network prefix
1624 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1625 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1626 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1627 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001628 if (matchDstIPv4Net != null) {
1629 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1630 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001631
1632 // Match the Source MAC address
1633 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1634 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1635 matchSrcMac = flowPathMatch.srcMac();
1636 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001637 if (matchSrcMac != null) {
1638 match.setDataLayerSource(matchSrcMac.toString());
1639 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1640 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001641
1642 // Match the Destination MAC address
1643 MACAddress matchDstMac = flowEntryMatch.dstMac();
1644 if ((matchDstMac == null) && (flowPathMatch != null)) {
1645 matchDstMac = flowPathMatch.dstMac();
1646 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001647 if (matchDstMac != null) {
1648 match.setDataLayerDestination(matchDstMac.toString());
1649 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1650 }
1651
1652 //
1653 // Fetch the actions
1654 //
1655 // TODO: For now we support only the "OUTPUT" actions.
1656 //
1657 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1658 List<OFAction> actions = new ArrayList<OFAction>();
1659 ArrayList<FlowEntryAction> flowEntryActions =
1660 flowEntry.flowEntryActions();
1661 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1662 FlowEntryAction.ActionOutput actionOutput =
1663 flowEntryAction.actionOutput();
1664 if (actionOutput != null) {
1665 short actionOutputPort = actionOutput.port().value();
1666 OFActionOutput action = new OFActionOutput();
1667 // XXX: The max length is hard-coded for now
1668 action.setMaxLength((short)0xffff);
1669 action.setPort(actionOutputPort);
1670 actions.add(action);
1671 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1672 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1673 fm.setOutPort(actionOutputPort);
1674 }
1675 }
1676 }
1677
1678 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1679 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1680 .setPriority(PRIORITY_DEFAULT)
1681 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1682 .setCookie(cookie)
1683 .setCommand(flowModCommand)
1684 .setMatch(match)
1685 .setActions(actions)
1686 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1687
1688 //
1689 // TODO: Set the following flag
1690 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1691 // See method ForwardingBase::pushRoute()
1692 //
1693
1694 //
1695 // Write the message to the switch
1696 //
1697 try {
1698 messageDamper.write(mySwitch, fm, null);
1699 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001700 //
1701 // TODO: We should use the OpenFlow Barrier mechanism
1702 // to check for errors, and update the SwitchState
1703 // for a flow entry after the Barrier message is
1704 // is received.
1705 //
1706 // TODO: The FlowEntry Object in Titan should be set
1707 // to FE_SWITCH_UPDATED.
1708 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001709 } catch (IOException e) {
1710 log.error("Failure writing flow mod from network map", e);
1711 return false;
1712 }
1713 return true;
1714 }
1715
1716 /**
1717 * Remove a Flow Entry from a switch.
1718 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001719 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001720 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001721 * @param flowEntry the flow entry to remove.
1722 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001723 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001724 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1725 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001726 //
1727 // The installFlowEntry() method implements both installation
1728 // and removal of flow entries.
1729 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001730 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001731 }
1732
1733 /**
1734 * Install a Flow Entry on a remote controller.
1735 *
1736 * TODO: We need it now: Jono
1737 * - For now it will make a REST call to the remote controller.
1738 * - Internally, it needs to know the name of the remote controller.
1739 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001740 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001741 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001742 * @return true on success, otherwise false.
1743 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001744 public boolean installRemoteFlowEntry(FlowPath flowPath,
1745 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001746 // TODO: We need it now: Jono
1747 // - For now it will make a REST call to the remote controller.
1748 // - Internally, it needs to know the name of the remote controller.
1749 return true;
1750 }
1751
1752 /**
1753 * Remove a flow entry on a remote controller.
1754 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001755 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001756 * @param flowEntry the flow entry to remove.
1757 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001758 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001759 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1760 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001761 //
1762 // The installRemoteFlowEntry() method implements both installation
1763 // and removal of flow entries.
1764 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001765 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001766 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001767}