blob: 9a5129f824ddc6cdeb819bf449fb950a383e0edf [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++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000134 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700135 String userState = flowEntryObj.getUserState();
136 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000137 String dpidStr = flowEntryObj.getSwitchDpid();
138 if ((flowEntryIdStr == null) ||
139 (userState == null) ||
140 (switchState == null) ||
141 (dpidStr == null)) {
142 log.debug("IGNORING Flow Entry entry with null fields");
143 continue;
144 }
145 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
146 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800147
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000148 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
149 continue; // Ignore the entry: nothing to do
150
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800151 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000152 if (mySwitch == null)
153 continue; // Ignore the entry: not my switch
154
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700155 IFlowPath flowObj =
156 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
157 if (flowObj == null)
158 continue; // Should NOT happen
159 if (flowObj.getFlowId() == null)
160 continue; // Invalid entry
161
162 //
163 // NOTE: For now we process the DELETE before the ADD
164 // to cover the more common scenario.
165 // TODO: This is error prone and needs to be fixed!
166 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700167 if (userState.equals("FE_USER_DELETE")) {
168 // An entry that needs to be deleted.
169 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700170 installFlowEntry(mySwitch, flowObj, flowEntryObj);
171 } else {
172 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700173 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700174 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700175 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700176 // TODO: Commented-out for now
177 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700178 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700179 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700180 processed_measurement_flow = true;
181 }
182 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700183 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700184 }
185
186 /*
187 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
188 addFlowEntries.size() + deleteFlowEntries.size());
189 */
190
191 //
192 // Process the Flow Entries that need to be added
193 //
194 for (IFlowEntry flowEntryObj : addFlowEntries) {
195 IFlowPath flowObj =
196 conn.utils().getFlowPathByFlowEntry(conn,
197 flowEntryObj);
198 if (flowObj == null)
199 continue; // Should NOT happen
200 if (flowObj.getFlowId() == null)
201 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700203 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700204 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000205 if (mySwitch == null)
206 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700207 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800208 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000209
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700210 /*
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700211 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
212 deleteFlowEntries.size());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700213 */
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700214
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000215 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700216 // Delete all entries marked for deletion from the
217 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000218 //
219 // TODO: We should use the OpenFlow Barrier mechanism
220 // to check for errors, and delete the Flow Entries after the
221 // Barrier message is received.
222 //
223 while (! deleteFlowEntries.isEmpty()) {
224 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
225 IFlowPath flowObj =
226 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
227 if (flowObj == null) {
228 log.debug("Did not find FlowPath to be deleted");
229 continue;
230 }
231 flowObj.removeFlowEntry(flowEntryObj);
232 conn.utils().removeFlowEntry(conn, flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000233 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700234
235
236 //
237 // Fetch and recompute the Shortest Path for those
238 // Flow Paths this controller is responsible for.
239 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700240 topoRouteService.prepareShortestPathTopo();
241 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700242 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700243 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700244 if (flowPathObj == null)
245 continue;
246 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
247 if (dataPathSummaryStr == null)
248 continue; // Could be invalid entry?
249 if (dataPathSummaryStr.isEmpty())
250 continue; // No need to maintain this flow
251
252 // Fetch the fields needed to recompute the shortest path
253 String flowIdStr = flowPathObj.getFlowId();
254 String srcDpidStr = flowPathObj.getSrcSwitch();
255 Short srcPortShort = flowPathObj.getSrcPort();
256 String dstDpidStr = flowPathObj.getDstSwitch();
257 Short dstPortShort = flowPathObj.getDstPort();
258 if ((flowIdStr == null) ||
259 (srcDpidStr == null) ||
260 (srcPortShort == null) ||
261 (dstDpidStr == null) ||
262 (dstPortShort == null)) {
263 log.debug("IGNORING Flow Path entry with null fields");
264 continue;
265 }
266
267 FlowId flowId = new FlowId(flowIdStr);
268 Dpid srcDpid = new Dpid(srcDpidStr);
269 Port srcPort = new Port(srcPortShort);
270 Dpid dstDpid = new Dpid(dstDpidStr);
271 Port dstPort = new Port(dstPortShort);
272 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
273 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700274
275 //
276 // Use the source DPID as a heuristic to decide
277 // which controller is responsible for maintaining the
278 // shortest path.
279 // NOTE: This heuristic is error-prone: if the switch
280 // goes away and no controller is responsible for that
281 // switch, then the original Flow Path is not cleaned-up
282 //
283 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
284 if (mySwitch == null)
285 continue; // Ignore: not my responsibility
286
287 counterMyFlowPaths++;
288
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700289 //
290 // NOTE: Using here the regular getShortestPath() method
291 // won't work here, because that method calls internally
292 // "conn.endTx(Transaction.COMMIT)", and that will
293 // invalidate all handlers to the Titan database.
294 // If we want to experiment with calling here
295 // getShortestPath(), we need to refactor that code
296 // to avoid closing the transaction.
297 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700298 DataPath dataPath =
299 topoRouteService.getTopoShortestPath(srcSwitchPort,
300 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000301 if (dataPath == null) {
302 // We need the DataPath to compare the paths
303 dataPath = new DataPath();
304 dataPath.setSrcPort(srcSwitchPort);
305 dataPath.setDstPort(dstSwitchPort);
306 }
307
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700308 String newDataPathSummaryStr = dataPath.dataPathSummary();
309 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
310 continue; // Nothing changed
311
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700312 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
313 flowId.toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700314 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700315 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700316 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700317
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800318 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700319
320 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700321 long estimatedTime =
322 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700323 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
324 (double)estimatedTime / 1000000000 + " sec";
325 log.debug(logMsg);
326 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700327
328 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700329 double rate = 0.0;
330 if (estimatedTime > 0)
331 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
332 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
333 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
334 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
335 counterAllFlowPaths + " MyFlowPaths: " +
336 counterMyFlowPaths + " in " +
337 (double)estimatedTime / 1000000000 + " sec: " +
338 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700339 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800340 }
341 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700342
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700343 final ScheduledFuture<?> mapReaderHandle =
344 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800345
346 @Override
347 public void init(String conf) {
348 conn = GraphDBConnection.getInstance(conf);
349 }
350
351 public void finalize() {
352 close();
353 }
354
355 @Override
356 public void close() {
357 conn.close();
358 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800359
360 @Override
361 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
362 Collection<Class<? extends IFloodlightService>> l =
363 new ArrayList<Class<? extends IFloodlightService>>();
364 l.add(IFlowService.class);
365 return l;
366 }
367
368 @Override
369 public Map<Class<? extends IFloodlightService>, IFloodlightService>
370 getServiceImpls() {
371 Map<Class<? extends IFloodlightService>,
372 IFloodlightService> m =
373 new HashMap<Class<? extends IFloodlightService>,
374 IFloodlightService>();
375 m.put(IFlowService.class, this);
376 return m;
377 }
378
379 @Override
380 public Collection<Class<? extends IFloodlightService>>
381 getModuleDependencies() {
382 Collection<Class<? extends IFloodlightService>> l =
383 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800384 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700385 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800386 l.add(IRestApiService.class);
387 return l;
388 }
389
390 @Override
391 public void init(FloodlightModuleContext context)
392 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700393 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800394 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700395 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800396 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800397 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
398 EnumSet.of(OFType.FLOW_MOD),
399 OFMESSAGE_DAMPER_TIMEOUT);
400 // TODO: An ugly hack!
401 String conf = "/tmp/cassandra.titan";
402 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800403 }
404
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000405 private long getNextFlowEntryId() {
406 //
407 // Generate the next Flow Entry ID.
408 // NOTE: For now, the higher 32 bits are random, and
409 // the lower 32 bits are sequential.
410 // In the future, we need a better allocation mechanism.
411 //
412 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
413 nextFlowEntryIdPrefix = randomGenerator.nextInt();
414 nextFlowEntryIdSuffix = 0;
415 } else {
416 nextFlowEntryIdSuffix++;
417 }
418 long result = (long)nextFlowEntryIdPrefix << 32;
419 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
420 return result;
421 }
422
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800423 @Override
424 public void startUp(FloodlightModuleContext context) {
425 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700426
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000427 // Initialize the Flow Entry ID generator
428 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800429 }
430
431 /**
432 * Add a flow.
433 *
434 * Internally, ONOS will automatically register the installer for
435 * receiving Flow Path Notifications for that path.
436 *
437 * @param flowPath the Flow Path to install.
438 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700439 * @param dataPathSummaryStr the data path summary string if the added
440 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800441 * @return true on success, otherwise false.
442 */
443 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700444 public boolean addFlow(FlowPath flowPath, FlowId flowId,
445 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700446 /*
447 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700448 if (flowPath.flowId().value() == measurementFlowId) {
449 modifiedMeasurementFlowTime = System.nanoTime();
450 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700451 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800452
453 IFlowPath flowObj = null;
454 try {
455 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
456 != null) {
457 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
458 flowPath.flowId().toString());
459 } else {
460 flowObj = conn.utils().newFlowPath(conn);
461 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
462 flowPath.flowId().toString());
463 }
464 } catch (Exception e) {
465 // TODO: handle exceptions
466 conn.endTx(Transaction.ROLLBACK);
467 log.error(":addFlow FlowId:{} failed",
468 flowPath.flowId().toString());
469 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700470 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000471 log.error(":addFlow FlowId:{} failed: Flow object not created",
472 flowPath.flowId().toString());
473 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800474 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700475 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800476
477 //
478 // Set the Flow key:
479 // - flowId
480 //
481 flowObj.setFlowId(flowPath.flowId().toString());
482 flowObj.setType("flow");
483
484 //
485 // Set the Flow attributes:
486 // - flowPath.installerId()
487 // - flowPath.dataPath().srcPort()
488 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700489 // - flowPath.matchEthernetFrameType()
490 // - flowPath.matchSrcIPv4Net()
491 // - flowPath.matchDstIPv4Net()
492 // - flowPath.matchSrcMac()
493 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800494 //
495 flowObj.setInstallerId(flowPath.installerId().toString());
496 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
497 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
498 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
499 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700500 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
501 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
502 }
503 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
504 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
505 }
506 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
507 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
508 }
509 if (flowPath.flowEntryMatch().matchSrcMac()) {
510 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
511 }
512 if (flowPath.flowEntryMatch().matchDstMac()) {
513 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
514 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800515
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700516 if (dataPathSummaryStr != null) {
517 flowObj.setDataPathSummary(dataPathSummaryStr);
518 } else {
519 flowObj.setDataPathSummary("");
520 }
521
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800522 // Flow edges:
523 // HeadFE
524
525
526 //
527 // Flow Entries:
528 // flowPath.dataPath().flowEntries()
529 //
530 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700531 if (addFlowEntry(flowObj, flowEntry) == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000532 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800533 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700534 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800535 }
536 conn.endTx(Transaction.COMMIT);
537
538 //
539 // TODO: We need a proper Flow ID allocation mechanism.
540 //
541 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700542
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800543 return true;
544 }
545
546 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700547 * Add a flow entry to the Network MAP.
548 *
549 * @param flowObj the corresponding Flow Path object for the Flow Entry.
550 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700551 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700552 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700553 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700554 // Flow edges
555 // HeadFE (TODO)
556
557 //
558 // Assign the FlowEntry ID.
559 //
560 if ((flowEntry.flowEntryId() == null) ||
561 (flowEntry.flowEntryId().value() == 0)) {
562 long id = getNextFlowEntryId();
563 flowEntry.setFlowEntryId(new FlowEntryId(id));
564 }
565
566 IFlowEntry flowEntryObj = null;
567 boolean found = false;
568 try {
569 if ((flowEntryObj =
570 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
571 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
572 flowEntry.flowEntryId().toString());
573 found = true;
574 } else {
575 flowEntryObj = conn.utils().newFlowEntry(conn);
576 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
577 flowEntry.flowEntryId().toString());
578 }
579 } catch (Exception e) {
580 log.error(":addFlow FlowEntryId:{} failed",
581 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700582 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700583 }
584 if (flowEntryObj == null) {
585 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
586 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700587 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700588 }
589
590 //
591 // Set the Flow Entry key:
592 // - flowEntry.flowEntryId()
593 //
594 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
595 flowEntryObj.setType("flow_entry");
596
597 //
598 // Set the Flow Entry Edges and attributes:
599 // - Switch edge
600 // - InPort edge
601 // - OutPort edge
602 //
603 // - flowEntry.flowEntryMatch()
604 // - flowEntry.flowEntryActions()
605 // - flowEntry.dpid()
606 // - flowEntry.flowEntryUserState()
607 // - flowEntry.flowEntrySwitchState()
608 // - flowEntry.flowEntryErrorState()
609 // - flowEntry.matchInPort()
610 // - flowEntry.matchEthernetFrameType()
611 // - flowEntry.matchSrcIPv4Net()
612 // - flowEntry.matchDstIPv4Net()
613 // - flowEntry.matchSrcMac()
614 // - flowEntry.matchDstMac()
615 // - flowEntry.actionOutput()
616 //
617 ISwitchObject sw =
618 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
619 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
620 flowEntryObj.setSwitch(sw);
621 if (flowEntry.flowEntryMatch().matchInPort()) {
622 IPortObject inport =
623 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
624 flowEntry.flowEntryMatch().inPort().value());
625 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
626 flowEntryObj.setInPort(inport);
627 }
628 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
629 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
630 }
631 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
632 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
633 }
634 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
635 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
636 }
637 if (flowEntry.flowEntryMatch().matchSrcMac()) {
638 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
639 }
640 if (flowEntry.flowEntryMatch().matchDstMac()) {
641 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
642 }
643
644 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
645 if (fa.actionOutput() != null) {
646 IPortObject outport =
647 conn.utils().searchPort(conn,
648 flowEntry.dpid().toString(),
649 fa.actionOutput().port().value());
650 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
651 flowEntryObj.setOutPort(outport);
652 }
653 }
654 // TODO: Hacks with hard-coded state names!
655 if (found)
656 flowEntryObj.setUserState("FE_USER_MODIFY");
657 else
658 flowEntryObj.setUserState("FE_USER_ADD");
659 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
660 //
661 // TODO: Take care of the FlowEntryErrorState.
662 //
663
664 // Flow Entries edges:
665 // Flow
666 // NextFE (TODO)
667 if (! found) {
668 flowObj.addFlowEntry(flowEntryObj);
669 flowEntryObj.setFlow(flowObj);
670 }
671
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700672 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700673 }
674
675 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800676 * Delete a previously added flow.
677 *
678 * @param flowId the Flow ID of the flow to delete.
679 * @return true on success, otherwise false.
680 */
681 @Override
682 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700683 /*
684 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700685 if (flowId.value() == measurementFlowId) {
686 modifiedMeasurementFlowTime = System.nanoTime();
687 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700688 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700689
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800690 IFlowPath flowObj = null;
691 //
692 // We just mark the entries for deletion,
693 // and let the switches remove each individual entry after
694 // it has been removed from the switches.
695 //
696 try {
697 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
698 != null) {
699 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
700 flowId.toString());
701 } else {
702 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
703 flowId.toString());
704 }
705 } catch (Exception e) {
706 // TODO: handle exceptions
707 conn.endTx(Transaction.ROLLBACK);
708 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
709 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700710 if (flowObj == null) {
711 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800712 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700713 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800714
715 //
716 // Find and mark for deletion all Flow Entries
717 //
718 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
719 boolean empty = true; // TODO: an ugly hack
720 for (IFlowEntry flowEntryObj : flowEntries) {
721 empty = false;
722 // flowObj.removeFlowEntry(flowEntryObj);
723 // conn.utils().removeFlowEntry(conn, flowEntryObj);
724 flowEntryObj.setUserState("FE_USER_DELETE");
725 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
726 }
727 // Remove from the database empty flows
728 if (empty)
729 conn.utils().removeFlowPath(conn, flowObj);
730 conn.endTx(Transaction.COMMIT);
731
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800732 return true;
733 }
734
735 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700736 * Clear the state for a previously added flow.
737 *
738 * @param flowId the Flow ID of the flow to clear.
739 * @return true on success, otherwise false.
740 */
741 @Override
742 public boolean clearFlow(FlowId flowId) {
743 IFlowPath flowObj = null;
744 try {
745 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
746 != null) {
747 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
748 flowId.toString());
749 } else {
750 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
751 flowId.toString());
752 }
753 } catch (Exception e) {
754 // TODO: handle exceptions
755 conn.endTx(Transaction.ROLLBACK);
756 log.error(":clearFlow FlowId:{} failed", flowId.toString());
757 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700758 if (flowObj == null) {
759 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700760 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700761 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700762
763 //
764 // Remove all Flow Entries
765 //
766 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
767 for (IFlowEntry flowEntryObj : flowEntries) {
768 flowObj.removeFlowEntry(flowEntryObj);
769 conn.utils().removeFlowEntry(conn, flowEntryObj);
770 }
771 // Remove the Flow itself
772 conn.utils().removeFlowPath(conn, flowObj);
773 conn.endTx(Transaction.COMMIT);
774
775 return true;
776 }
777
778 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800779 * Get a previously added flow.
780 *
781 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800782 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800783 */
784 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800785 public FlowPath getFlow(FlowId flowId) {
786 IFlowPath flowObj = null;
787 try {
788 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
789 != null) {
790 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
791 flowId.toString());
792 } else {
793 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
794 flowId.toString());
795 }
796 } catch (Exception e) {
797 // TODO: handle exceptions
798 conn.endTx(Transaction.ROLLBACK);
799 log.error(":getFlow FlowId:{} failed", flowId.toString());
800 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700801 if (flowObj == null) {
802 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800803 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700804 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800805
806 //
807 // Extract the Flow state
808 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800809 FlowPath flowPath = extractFlowPath(flowObj);
810 conn.endTx(Transaction.COMMIT);
811
812 return flowPath;
813 }
814
815 /**
816 * Get all previously added flows by a specific installer for a given
817 * data path endpoints.
818 *
819 * @param installerId the Caller ID of the installer of the flow to get.
820 * @param dataPathEndpoints the data path endpoints of the flow to get.
821 * @return the Flow Paths if found, otherwise null.
822 */
823 @Override
824 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
825 DataPathEndpoints dataPathEndpoints) {
826 //
827 // TODO: The implementation below is not optimal:
828 // We fetch all flows, and then return only the subset that match
829 // the query conditions.
830 // We should use the appropriate Titan/Gremlin query to filter-out
831 // the flows as appropriate.
832 //
833 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700834 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800835
836 if (allFlows == null) {
837 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700838 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800839 }
840
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800841 for (FlowPath flow : allFlows) {
842 //
843 // TODO: String-based comparison is sub-optimal.
844 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800845 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800846 //
847 if (! flow.installerId().toString().equals(installerId.toString()))
848 continue;
849 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
850 continue;
851 }
852 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
853 continue;
854 }
855 flowPaths.add(flow);
856 }
857
858 if (flowPaths.isEmpty()) {
859 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800860 } else {
861 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
862 }
863
864 return flowPaths;
865 }
866
867 /**
868 * Get all installed flows by all installers for given data path endpoints.
869 *
870 * @param dataPathEndpoints the data path endpoints of the flows to get.
871 * @return the Flow Paths if found, otherwise null.
872 */
873 @Override
874 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
875 //
876 // TODO: The implementation below is not optimal:
877 // We fetch all flows, and then return only the subset that match
878 // the query conditions.
879 // We should use the appropriate Titan/Gremlin query to filter-out
880 // the flows as appropriate.
881 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700882 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
883 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800884
885 if (allFlows == null) {
886 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700887 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800888 }
889
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800890 for (FlowPath flow : allFlows) {
891 //
892 // TODO: String-based comparison is sub-optimal.
893 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800894 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800895 //
896 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
897 continue;
898 }
899 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
900 continue;
901 }
902 flowPaths.add(flow);
903 }
904
905 if (flowPaths.isEmpty()) {
906 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800907 } else {
908 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
909 }
910
911 return flowPaths;
912 }
913
914 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700915 * Get summary of all installed flows by all installers in a given range
916 *
917 * @param flowId the data path endpoints of the flows to get.
918 * @param maxFlows: the maximum number of flows to be returned
919 * @return the Flow Paths if found, otherwise null.
920 */
921 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -0700922 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700923
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700924 // TODO: The implementation below is not optimal:
925 // We fetch all flows, and then return only the subset that match
926 // the query conditions.
927 // We should use the appropriate Titan/Gremlin query to filter-out
928 // the flows as appropriate.
929 //
Jonathan Hart01f2d272013-04-04 20:03:46 -0700930 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700931
Jonathan Hart01f2d272013-04-04 20:03:46 -0700932 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
933
Jonathan Hartf5315fb2013-04-05 11:41:56 -0700934 Collections.sort(flowPathsWithoutFlowEntries,
935 new Comparator<IFlowPath>(){
936 @Override
937 public int compare(IFlowPath first, IFlowPath second) {
938 // TODO Auto-generated method stub
939 long result = new FlowId(first.getFlowId()).value()
940 - new FlowId(second.getFlowId()).value();
941 if (result > 0) return 1;
942 else if (result < 0) return -1;
943 else return 0;
944 }
945 }
946 );
947
Jonathan Hart01f2d272013-04-04 20:03:46 -0700948 return flowPathsWithoutFlowEntries;
949
950 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700951 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -0700952
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700953 if (allFlows == null) {
954 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700955 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700956 }
957
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700958 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700959
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700960 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700961 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700962
Pavlin Radoslavov96b43422013-04-04 19:14:56 -0700963 // start from desired flowId
964 if (flow.flowId().value() < flowId.value()) {
965 continue;
966 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700967
968 // Summarize by making null flow entry fields that are not relevant to report
969 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
970 flowEntry.setFlowEntryActions(null);
971 flowEntry.setFlowEntryMatch(null);
972 }
973
974 flowPaths.add(flow);
975 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
976 break;
977 }
978 }
979
980 if (flowPaths.isEmpty()) {
981 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700982 } else {
983 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
984 }
985
986 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -0700987 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700988 }
989
990 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800991 * Get all installed flows by all installers.
992 *
993 * @return the Flow Paths if found, otherwise null.
994 */
995 @Override
996 public ArrayList<FlowPath> getAllFlows() {
997 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700998 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800999
1000 try {
1001 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1002 log.debug("Get all FlowPaths: found FlowPaths");
1003 } else {
1004 log.debug("Get all FlowPaths: no FlowPaths found");
1005 }
1006 } catch (Exception e) {
1007 // TODO: handle exceptions
1008 conn.endTx(Transaction.ROLLBACK);
1009 log.error(":getAllFlowPaths failed");
1010 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001011 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1012 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001013 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001014 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001015
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001016 for (IFlowPath flowObj : flowPathsObj) {
1017 //
1018 // Extract the Flow state
1019 //
1020 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001021 if (flowPath != null)
1022 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001023 }
1024
1025 conn.endTx(Transaction.COMMIT);
1026
1027 return flowPaths;
1028 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001029
1030 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1031 Iterable<IFlowPath> flowPathsObj = null;
1032 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1033 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1034
1035 try {
1036 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
1037 log.debug("Get all FlowPaths: found FlowPaths");
1038 } else {
1039 log.debug("Get all FlowPaths: no FlowPaths found");
1040 }
1041 } catch (Exception e) {
1042 // TODO: handle exceptions
1043 conn.endTx(Transaction.ROLLBACK);
1044 log.error(":getAllFlowPaths failed");
1045 }
1046 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1047 return new ArrayList<IFlowPath>(); // No Flows found
1048 }
1049
1050 for (IFlowPath flowObj : flowPathsObj){
1051 flowPathsObjArray.add(flowObj);
1052 }
1053 /*
1054 for (IFlowPath flowObj : flowPathsObj) {
1055 //
1056 // Extract the Flow state
1057 //
1058 FlowPath flowPath = extractFlowPath(flowObj);
1059 if (flowPath != null)
1060 flowPaths.add(flowPath);
1061 }
1062 */
1063
1064 //conn.endTx(Transaction.COMMIT);
1065
1066 return flowPathsObjArray;
1067 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001068
1069 /**
1070 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1071 *
1072 * @param flowObj the object to extract the Flow Path State from.
1073 * @return the extracted Flow Path State.
1074 */
1075 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001076 //
1077 // Extract the Flow state
1078 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001079 String flowIdStr = flowObj.getFlowId();
1080 String installerIdStr = flowObj.getInstallerId();
1081 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001082 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001083 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001084 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001085
1086 if ((flowIdStr == null) ||
1087 (installerIdStr == null) ||
1088 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001089 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001090 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001091 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001092 // TODO: A work-around, becauuse of some bogus database objects
1093 return null;
1094 }
1095
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001096 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001097 flowPath.setFlowId(new FlowId(flowIdStr));
1098 flowPath.setInstallerId(new CallerId(installerIdStr));
1099 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001100 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001101 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001102 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001103 //
1104 // Extract the match conditions common for all Flow Entries
1105 //
1106 {
1107 FlowEntryMatch match = new FlowEntryMatch();
1108 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1109 if (matchEthernetFrameType != null)
1110 match.enableEthernetFrameType(matchEthernetFrameType);
1111 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1112 if (matchSrcIPv4Net != null)
1113 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1114 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1115 if (matchDstIPv4Net != null)
1116 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1117 String matchSrcMac = flowObj.getMatchSrcMac();
1118 if (matchSrcMac != null)
1119 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1120 String matchDstMac = flowObj.getMatchDstMac();
1121 if (matchDstMac != null)
1122 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1123 flowPath.setFlowEntryMatch(match);
1124 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001125
1126 //
1127 // Extract all Flow Entries
1128 //
1129 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1130 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001131 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1132 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001133 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001134 flowPath.dataPath().flowEntries().add(flowEntry);
1135 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001136
1137 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001138 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001139
1140 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001141 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1142 *
1143 * @param flowEntryObj the object to extract the Flow Entry State from.
1144 * @return the extracted Flow Entry State.
1145 */
1146 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1147 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1148 String switchDpidStr = flowEntryObj.getSwitchDpid();
1149 String userState = flowEntryObj.getUserState();
1150 String switchState = flowEntryObj.getSwitchState();
1151
1152 if ((flowEntryIdStr == null) ||
1153 (switchDpidStr == null) ||
1154 (userState == null) ||
1155 (switchState == null)) {
1156 // TODO: A work-around, becauuse of some bogus database objects
1157 return null;
1158 }
1159
1160 FlowEntry flowEntry = new FlowEntry();
1161 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1162 flowEntry.setDpid(new Dpid(switchDpidStr));
1163
1164 //
1165 // Extract the match conditions
1166 //
1167 FlowEntryMatch match = new FlowEntryMatch();
1168 Short matchInPort = flowEntryObj.getMatchInPort();
1169 if (matchInPort != null)
1170 match.enableInPort(new Port(matchInPort));
1171 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1172 if (matchEthernetFrameType != null)
1173 match.enableEthernetFrameType(matchEthernetFrameType);
1174 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1175 if (matchSrcIPv4Net != null)
1176 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1177 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1178 if (matchDstIPv4Net != null)
1179 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1180 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1181 if (matchSrcMac != null)
1182 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1183 String matchDstMac = flowEntryObj.getMatchDstMac();
1184 if (matchDstMac != null)
1185 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1186 flowEntry.setFlowEntryMatch(match);
1187
1188 //
1189 // Extract the actions
1190 //
1191 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1192 Short actionOutputPort = flowEntryObj.getActionOutput();
1193 if (actionOutputPort != null) {
1194 FlowEntryAction action = new FlowEntryAction();
1195 action.setActionOutput(new Port(actionOutputPort));
1196 actions.add(action);
1197 }
1198 flowEntry.setFlowEntryActions(actions);
1199 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1200 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1201 //
1202 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1203 // and FlowEntryErrorState.
1204 //
1205 return flowEntry;
1206 }
1207
1208 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001209 * Add and maintain a shortest-path flow.
1210 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001211 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001212 *
1213 * @param flowPath the Flow Path with the endpoints and the match
1214 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001215 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001216 */
1217 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001218 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001219 String dataPathSummaryStr = null;
1220
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001221 //
1222 // Do the shortest path computation
1223 //
1224 DataPath dataPath =
1225 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1226 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001227 if (dataPath == null) {
1228 // We need the DataPath to populate the Network MAP
1229 dataPath = new DataPath();
1230 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1231 dataPath.setDstPort(flowPath.dataPath().dstPort());
1232 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001233
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001234 // Compute the Data Path summary
1235 dataPathSummaryStr = dataPath.dataPathSummary();
1236
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001237 //
1238 // Set the incoming port matching and the outgoing port output
1239 // actions for each flow entry.
1240 //
1241 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1242 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001243 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001244 flowEntry.setFlowEntryMatch(flowEntryMatch);
1245 flowEntryMatch.enableInPort(flowEntry.inPort());
1246
1247 // Set the outgoing port output action
1248 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1249 if (flowEntryActions == null) {
1250 flowEntryActions = new ArrayList<FlowEntryAction>();
1251 flowEntry.setFlowEntryActions(flowEntryActions);
1252 }
1253 FlowEntryAction flowEntryAction = new FlowEntryAction();
1254 flowEntryAction.setActionOutput(flowEntry.outPort());
1255 flowEntryActions.add(flowEntryAction);
1256 }
1257
1258 //
1259 // Prepare the computed Flow Path
1260 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001261 FlowPath computedFlowPath = new FlowPath();
1262 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1263 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1264 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001265 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001266
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001267 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001268 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001269 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001270
1271 // TODO: Mark the flow for maintenance purpose
1272
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001273 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001274 }
1275
1276 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001277 * Reconcile a flow.
1278 *
1279 * @param flowObj the flow that needs to be reconciliated.
1280 * @param newDataPath the new data path to use.
1281 * @return true on success, otherwise false.
1282 */
1283 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1284 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1285
1286 //
1287 // Set the incoming port matching and the outgoing port output
1288 // actions for each flow entry.
1289 //
1290 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1291 // Set the incoming port matching
1292 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1293 flowEntry.setFlowEntryMatch(flowEntryMatch);
1294 flowEntryMatch.enableInPort(flowEntry.inPort());
1295
1296 // Set the outgoing port output action
1297 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1298 if (flowEntryActions == null) {
1299 flowEntryActions = new ArrayList<FlowEntryAction>();
1300 flowEntry.setFlowEntryActions(flowEntryActions);
1301 }
1302 FlowEntryAction flowEntryAction = new FlowEntryAction();
1303 flowEntryAction.setActionOutput(flowEntry.outPort());
1304 flowEntryActions.add(flowEntryAction);
1305 }
1306
1307 //
1308 // Remove the old Flow Entries, and add the new Flow Entries
1309 //
1310
1311 //
1312 // Remove the Flow Entries from the Network MAP
1313 //
1314 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1315 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1316 for (IFlowEntry flowEntryObj : flowEntries) {
1317 String dpidStr = flowEntryObj.getSwitchDpid();
1318 if (dpidStr == null)
1319 continue;
1320 Dpid dpid = new Dpid(dpidStr);
1321 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1322
1323 flowEntryObj.setUserState("FE_USER_DELETE");
1324 if (mySwitch == null) {
1325 //
1326 // Not my switch. Mark it for deletion in the Network MAP
1327 //
1328 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1329 continue;
1330 }
1331
1332 deleteFlowEntries.add(flowEntryObj);
1333
1334 //
1335 // Delete the flow entry from the switch
1336 //
1337 // flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
1338 installFlowEntry(mySwitch, flowObj, flowEntryObj);
1339 // flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1340 }
1341 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
1342 flowObj.removeFlowEntry(flowEntryObj);
1343 conn.utils().removeFlowEntry(conn, flowEntryObj);
1344 }
1345
1346 //
1347 // Install the new shortest path into the Network MAP and the switches.
1348 //
1349 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1350 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
1351 IFlowEntry flowEntryObj = addFlowEntry(flowObj, flowEntry);
1352 if (flowEntryObj == null) {
1353 //
1354 // TODO: Remove the "new Object[] wrapper in the statement
1355 // below after the SLF4J logger is upgraded to
1356 // Version 1.7.5
1357 //
1358 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1359 new Object[] {
1360 flowEntry.dpid(),
1361 newDataPath.srcPort(),
1362 newDataPath.dstPort()
1363 });
1364 continue;
1365 }
1366
1367 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1368 if (mySwitch == null) {
1369 // Not my switch: just add to the Network MAP
1370 continue;
1371 }
1372
1373 // Install the Flow Entry into the switch
1374 if (installFlowEntry(mySwitch, flowObj, flowEntryObj)) {
1375 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1376 }
1377 }
1378
1379 //
1380 // Set the Data Path Summary
1381 //
1382 String dataPathSummaryStr = newDataPath.dataPathSummary();
1383 flowObj.setDataPathSummary(dataPathSummaryStr);
1384
1385 return true;
1386 }
1387
1388 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001389 * Reconcile all flows in a set.
1390 *
1391 * @param flowObjSet the set of flows that need to be reconciliated.
1392 */
1393 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1394 if (! flowObjSet.iterator().hasNext())
1395 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001396 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001397 }
1398
1399 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001400 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001401 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001402 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001403 * @param flowObj the flow path object for the flow entry to install.
1404 * @param flowEntryObj the flow entry object to install.
1405 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001406 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001407 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1408 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001409 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1410 if (flowEntryIdStr == null)
1411 return false;
1412 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001413 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001414 if (userState == null)
1415 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001416
1417 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001418 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001419 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001420 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1421 .getMessage(OFType.FLOW_MOD);
1422 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001424 short flowModCommand = OFFlowMod.OFPFC_ADD;
1425 if (userState.equals("FE_USER_ADD")) {
1426 flowModCommand = OFFlowMod.OFPFC_ADD;
1427 } else if (userState.equals("FE_USER_MODIFY")) {
1428 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1429 } else if (userState.equals("FE_USER_DELETE")) {
1430 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1431 } else {
1432 // Unknown user state. Ignore the entry
1433 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1434 flowEntryId.toString(), userState);
1435 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001436 }
1437
1438 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001439 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001440 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001441 // NOTE: The Flow matching conditions common for all Flow Entries are
1442 // used ONLY if a Flow Entry does NOT have the corresponding matching
1443 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001444 //
1445 OFMatch match = new OFMatch();
1446 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001447
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001448 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001449 Short matchInPort = flowEntryObj.getMatchInPort();
1450 if (matchInPort != null) {
1451 match.setInputPort(matchInPort);
1452 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1453 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001454
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001455 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001456 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1457 if (matchEthernetFrameType == null)
1458 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1459 if (matchEthernetFrameType != null) {
1460 match.setDataLayerType(matchEthernetFrameType);
1461 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1462 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001463
1464 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001465 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1466 if (matchSrcIPv4Net == null)
1467 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1468 if (matchSrcIPv4Net != null) {
1469 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1470 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001471
1472 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001473 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1474 if (matchDstIPv4Net == null)
1475 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1476 if (matchDstIPv4Net != null) {
1477 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1478 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001479
1480 // Match the Source MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001481 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1482 if (matchSrcMac == null)
1483 matchSrcMac = flowObj.getMatchSrcMac();
1484 if (matchSrcMac != null) {
1485 match.setDataLayerSource(matchSrcMac);
1486 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1487 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001488
1489 // Match the Destination MAC address
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001490 String matchDstMac = flowEntryObj.getMatchDstMac();
1491 if (matchDstMac == null)
1492 matchDstMac = flowObj.getMatchDstMac();
1493 if (matchDstMac != null) {
1494 match.setDataLayerDestination(matchDstMac);
1495 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1496 }
1497
1498 //
1499 // Fetch the actions
1500 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001501 // TODO: For now we support only the "OUTPUT" actions.
1502 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001503 List<OFAction> actions = new ArrayList<OFAction>();
1504 Short actionOutputPort = flowEntryObj.getActionOutput();
1505 if (actionOutputPort != null) {
1506 OFActionOutput action = new OFActionOutput();
1507 // XXX: The max length is hard-coded for now
1508 action.setMaxLength((short)0xffff);
1509 action.setPort(actionOutputPort);
1510 actions.add(action);
1511 }
1512
1513 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1514 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1515 .setPriority(PRIORITY_DEFAULT)
1516 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1517 .setCookie(cookie)
1518 .setCommand(flowModCommand)
1519 .setMatch(match)
1520 .setActions(actions)
1521 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1522 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1523 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1524 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1525 if (actionOutputPort != null)
1526 fm.setOutPort(actionOutputPort);
1527 }
1528
1529 //
1530 // TODO: Set the following flag
1531 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1532 // See method ForwardingBase::pushRoute()
1533 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001534
1535 //
1536 // Write the message to the switch
1537 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001538 log.debug("MEASUREMENT: Installing flow entry " + userState +
1539 " into switch DPID: " +
1540 mySwitch.getStringId() +
1541 " flowEntryId: " + flowEntryId.toString() +
1542 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1543 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1544 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001545 try {
1546 messageDamper.write(mySwitch, fm, null);
1547 mySwitch.flush();
1548 //
1549 // TODO: We should use the OpenFlow Barrier mechanism
1550 // to check for errors, and update the SwitchState
1551 // for a flow entry after the Barrier message is
1552 // is received.
1553 //
1554 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1555 } catch (IOException e) {
1556 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001557 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001558 }
1559
1560 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001561 }
1562
1563 /**
1564 * Install a Flow Entry on a switch.
1565 *
1566 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001567 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001568 * @param flowEntry the flow entry to install.
1569 * @return true on success, otherwise false.
1570 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001571 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1572 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001573 //
1574 // Create the OpenFlow Flow Modification Entry to push
1575 //
1576 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1577 .getMessage(OFType.FLOW_MOD);
1578 long cookie = flowEntry.flowEntryId().value();
1579
1580 short flowModCommand = OFFlowMod.OFPFC_ADD;
1581 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1582 flowModCommand = OFFlowMod.OFPFC_ADD;
1583 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1584 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1585 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1586 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1587 } else {
1588 // Unknown user state. Ignore the entry
1589 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1590 flowEntry.flowEntryId().toString(),
1591 flowEntry.flowEntryUserState());
1592 return false;
1593 }
1594
1595 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001596 // Fetch the match conditions.
1597 //
1598 // NOTE: The Flow matching conditions common for all Flow Entries are
1599 // used ONLY if a Flow Entry does NOT have the corresponding matching
1600 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001601 //
1602 OFMatch match = new OFMatch();
1603 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001604 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1605 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1606
1607 // Match the Incoming Port
1608 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001609 if (matchInPort != null) {
1610 match.setInputPort(matchInPort.value());
1611 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1612 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001613
1614 // Match the Ethernet Frame Type
1615 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1616 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1617 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1618 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001619 if (matchEthernetFrameType != null) {
1620 match.setDataLayerType(matchEthernetFrameType);
1621 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1622 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001623
1624 // Match the Source IPv4 Network prefix
1625 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1626 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1627 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1628 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001629 if (matchSrcIPv4Net != null) {
1630 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1631 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001632
1633 // Natch the Destination IPv4 Network prefix
1634 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1635 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1636 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1637 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001638 if (matchDstIPv4Net != null) {
1639 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1640 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001641
1642 // Match the Source MAC address
1643 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1644 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1645 matchSrcMac = flowPathMatch.srcMac();
1646 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001647 if (matchSrcMac != null) {
1648 match.setDataLayerSource(matchSrcMac.toString());
1649 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1650 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001651
1652 // Match the Destination MAC address
1653 MACAddress matchDstMac = flowEntryMatch.dstMac();
1654 if ((matchDstMac == null) && (flowPathMatch != null)) {
1655 matchDstMac = flowPathMatch.dstMac();
1656 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001657 if (matchDstMac != null) {
1658 match.setDataLayerDestination(matchDstMac.toString());
1659 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1660 }
1661
1662 //
1663 // Fetch the actions
1664 //
1665 // TODO: For now we support only the "OUTPUT" actions.
1666 //
1667 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1668 List<OFAction> actions = new ArrayList<OFAction>();
1669 ArrayList<FlowEntryAction> flowEntryActions =
1670 flowEntry.flowEntryActions();
1671 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1672 FlowEntryAction.ActionOutput actionOutput =
1673 flowEntryAction.actionOutput();
1674 if (actionOutput != null) {
1675 short actionOutputPort = actionOutput.port().value();
1676 OFActionOutput action = new OFActionOutput();
1677 // XXX: The max length is hard-coded for now
1678 action.setMaxLength((short)0xffff);
1679 action.setPort(actionOutputPort);
1680 actions.add(action);
1681 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1682 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1683 fm.setOutPort(actionOutputPort);
1684 }
1685 }
1686 }
1687
1688 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1689 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1690 .setPriority(PRIORITY_DEFAULT)
1691 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1692 .setCookie(cookie)
1693 .setCommand(flowModCommand)
1694 .setMatch(match)
1695 .setActions(actions)
1696 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1697
1698 //
1699 // TODO: Set the following flag
1700 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1701 // See method ForwardingBase::pushRoute()
1702 //
1703
1704 //
1705 // Write the message to the switch
1706 //
1707 try {
1708 messageDamper.write(mySwitch, fm, null);
1709 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001710 //
1711 // TODO: We should use the OpenFlow Barrier mechanism
1712 // to check for errors, and update the SwitchState
1713 // for a flow entry after the Barrier message is
1714 // is received.
1715 //
1716 // TODO: The FlowEntry Object in Titan should be set
1717 // to FE_SWITCH_UPDATED.
1718 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001719 } catch (IOException e) {
1720 log.error("Failure writing flow mod from network map", e);
1721 return false;
1722 }
1723 return true;
1724 }
1725
1726 /**
1727 * Remove a Flow Entry from a switch.
1728 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001729 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001730 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001731 * @param flowEntry the flow entry to remove.
1732 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001733 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001734 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1735 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001736 //
1737 // The installFlowEntry() method implements both installation
1738 // and removal of flow entries.
1739 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001740 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001741 }
1742
1743 /**
1744 * Install a Flow Entry on a remote controller.
1745 *
1746 * 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 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001750 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001751 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001752 * @return true on success, otherwise false.
1753 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001754 public boolean installRemoteFlowEntry(FlowPath flowPath,
1755 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001756 // TODO: We need it now: Jono
1757 // - For now it will make a REST call to the remote controller.
1758 // - Internally, it needs to know the name of the remote controller.
1759 return true;
1760 }
1761
1762 /**
1763 * Remove a flow entry on a remote controller.
1764 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001765 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001766 * @param flowEntry the flow entry to remove.
1767 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001768 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001769 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1770 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001771 //
1772 // The installRemoteFlowEntry() method implements both installation
1773 // and removal of flow entries.
1774 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001775 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001776 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001777}