blob: 5604e92bd0e35b78946019d5e686ce99bb3b84d1 [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;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +00006import java.util.Collections;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08007import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08008import java.util.HashMap;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07009import java.util.HashSet;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000010import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080012import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000013import java.util.Random;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070014import java.util.TreeMap;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070015import java.util.concurrent.BlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import java.util.concurrent.Executors;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070017import java.util.concurrent.LinkedBlockingQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080018import java.util.concurrent.ScheduledExecutorService;
19import java.util.concurrent.ScheduledFuture;
Pavlin Radoslavov4da61282013-03-20 20:31:36 -070020import java.util.concurrent.ThreadPoolExecutor;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080023import net.floodlightcontroller.core.IFloodlightProviderService;
24import net.floodlightcontroller.core.INetMapStorage;
25import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
26import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070027import net.floodlightcontroller.core.INetMapTopologyObjects.IPortObject;
Pankaj Berded0079742013-03-27 17:53:25 -070028import net.floodlightcontroller.core.INetMapTopologyObjects.ISwitchObject;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070029import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080030import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080031import net.floodlightcontroller.core.module.FloodlightModuleContext;
32import net.floodlightcontroller.core.module.FloodlightModuleException;
33import net.floodlightcontroller.core.module.IFloodlightModule;
34import net.floodlightcontroller.core.module.IFloodlightService;
35import net.floodlightcontroller.flowcache.IFlowService;
36import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
37import net.floodlightcontroller.restserver.IRestApiService;
38import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080039import net.floodlightcontroller.util.DataPath;
40import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080041import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080042import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070043import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080044import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070045import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.floodlightcontroller.util.FlowEntrySwitchState;
47import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080048import net.floodlightcontroller.util.FlowId;
49import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070050import net.floodlightcontroller.util.IPv4Net;
51import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080052import net.floodlightcontroller.util.OFMessageDamper;
53import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070054import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080055import net.onrc.onos.util.GraphDBConnection;
56import net.onrc.onos.util.GraphDBConnection.Transaction;
57
58import org.openflow.protocol.OFFlowMod;
59import org.openflow.protocol.OFMatch;
60import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070061import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080062import org.openflow.protocol.OFType;
63import org.openflow.protocol.action.OFAction;
64import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080065
66import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
68
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070069public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080070
71 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080072
73 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080074 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -070075 protected ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070076 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080077
78 protected OFMessageDamper messageDamper;
79
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070080 //
81 // TODO: Values copied from elsewhere (class LearningSwitch).
82 // The local copy should go away!
83 //
84 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
85 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
86 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
87 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
88 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080089
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000090 // Flow Entry ID generation state
91 private static Random randomGenerator = new Random();
92 private static int nextFlowEntryIdPrefix = 0;
93 private static int nextFlowEntryIdSuffix = 0;
94 private static long nextFlowEntryId = 0;
95
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070096 private static long measurementFlowId = 100000;
97 private static String measurementFlowIdStr = "0x186a0"; // 100000
98 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070099
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800100 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800101 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
102
103 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700104 private final ScheduledExecutorService mapReaderScheduler =
105 Executors.newScheduledThreadPool(1);
106
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700107 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800108 public void run() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700109 long startTime = System.nanoTime();
110 int counterAllFlowEntries = 0;
111 int counterMyNotUpdatedFlowEntries = 0;
112 int counterAllFlowPaths = 0;
113 int counterMyFlowPaths = 0;
114
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800115 if (floodlightProvider == null) {
116 log.debug("FloodlightProvider service not found!");
117 return;
118 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000119 Map<Long, IOFSwitch> mySwitches =
120 floodlightProvider.getSwitches();
121 Map<Long, IFlowEntry> myFlowEntries =
122 new TreeMap<Long, IFlowEntry>();
123 LinkedList<IFlowEntry> deleteFlowEntries =
124 new LinkedList<IFlowEntry>();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700125
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700126
127 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700128 // Fetch all Flow Entries and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700129 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700130 //
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000131 Iterable<IFlowEntry> allFlowEntries =
132 conn.utils().getAllFlowEntries(conn);
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700133 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700134 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000135 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700136 String userState = flowEntryObj.getUserState();
137 String switchState = flowEntryObj.getSwitchState();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000138 String dpidStr = flowEntryObj.getSwitchDpid();
139 if ((flowEntryIdStr == null) ||
140 (userState == null) ||
141 (switchState == null) ||
142 (dpidStr == null)) {
143 log.debug("IGNORING Flow Entry entry with null fields");
144 continue;
145 }
146 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
147 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800148
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000149 if (! switchState.equals("FE_SWITCH_NOT_UPDATED"))
150 continue; // Ignore the entry: nothing to do
151
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800152 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000153 if (mySwitch == null)
154 continue; // Ignore the entry: not my switch
155
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700156 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700157 if (userState.equals("FE_USER_DELETE")) {
158 // An entry that needs to be deleted.
159 deleteFlowEntries.add(flowEntryObj);
160 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700161 }
162
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700163 log.debug("MEASUREMENT: Found {} My Flow Entries NOT_UPDATED",
164 myFlowEntries.size());
165
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700166 //
167 // Process my Flow Entries
168 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700169 boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700170 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700171 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700172 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700173 IFlowPath flowObj =
174 conn.utils().getFlowPathByFlowEntry(conn,
175 flowEntryObj);
176 if (flowObj == null)
177 continue; // Should NOT happen
178
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700180 // TODO: Commented-out for now
181 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700182 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700183 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700184 processed_measurement_flow = true;
185 }
186 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700187 */
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700188
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700189 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700190 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000191 if (mySwitch == null)
192 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700193 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800194 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000195
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700196 log.debug("MEASUREMENT: Found {} Flow Entries to delete",
197 deleteFlowEntries.size());
198
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000199 //
200 // Delete all entries marked for deletion
201 //
202 // TODO: We should use the OpenFlow Barrier mechanism
203 // to check for errors, and delete the Flow Entries after the
204 // Barrier message is received.
205 //
206 while (! deleteFlowEntries.isEmpty()) {
207 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
208 IFlowPath flowObj =
209 conn.utils().getFlowPathByFlowEntry(conn, flowEntryObj);
210 if (flowObj == null) {
211 log.debug("Did not find FlowPath to be deleted");
212 continue;
213 }
214 flowObj.removeFlowEntry(flowEntryObj);
215 conn.utils().removeFlowEntry(conn, flowEntryObj);
216
217 // Test whether the last flow entry
218 Iterable<IFlowEntry> tmpflowEntries =
219 flowObj.getFlowEntries();
220 boolean found = false;
221 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
222 found = true;
223 break;
224 }
225 if (! found) {
226 // Remove the Flow Path as well
227 conn.utils().removeFlowPath(conn, flowObj);
228 }
229 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700230
231
232 //
233 // Fetch and recompute the Shortest Path for those
234 // Flow Paths this controller is responsible for.
235 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700236 topoRouteService.prepareShortestPathTopo();
237 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
238 HashSet<IFlowPath> flowObjSet = new HashSet<IFlowPath>();
239 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700240 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700241 if (flowPathObj == null)
242 continue;
243 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
244 if (dataPathSummaryStr == null)
245 continue; // Could be invalid entry?
246 if (dataPathSummaryStr.isEmpty())
247 continue; // No need to maintain this flow
248
249 // Fetch the fields needed to recompute the shortest path
250 String flowIdStr = flowPathObj.getFlowId();
251 String srcDpidStr = flowPathObj.getSrcSwitch();
252 Short srcPortShort = flowPathObj.getSrcPort();
253 String dstDpidStr = flowPathObj.getDstSwitch();
254 Short dstPortShort = flowPathObj.getDstPort();
255 if ((flowIdStr == null) ||
256 (srcDpidStr == null) ||
257 (srcPortShort == null) ||
258 (dstDpidStr == null) ||
259 (dstPortShort == null)) {
260 log.debug("IGNORING Flow Path entry with null fields");
261 continue;
262 }
263
264 FlowId flowId = new FlowId(flowIdStr);
265 Dpid srcDpid = new Dpid(srcDpidStr);
266 Port srcPort = new Port(srcPortShort);
267 Dpid dstDpid = new Dpid(dstDpidStr);
268 Port dstPort = new Port(dstPortShort);
269 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
270 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700271
272 //
273 // Use the source DPID as a heuristic to decide
274 // which controller is responsible for maintaining the
275 // shortest path.
276 // NOTE: This heuristic is error-prone: if the switch
277 // goes away and no controller is responsible for that
278 // switch, then the original Flow Path is not cleaned-up
279 //
280 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
281 if (mySwitch == null)
282 continue; // Ignore: not my responsibility
283
284 counterMyFlowPaths++;
285
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700286 //
287 // NOTE: Using here the regular getShortestPath() method
288 // won't work here, because that method calls internally
289 // "conn.endTx(Transaction.COMMIT)", and that will
290 // invalidate all handlers to the Titan database.
291 // If we want to experiment with calling here
292 // getShortestPath(), we need to refactor that code
293 // to avoid closing the transaction.
294 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700295 DataPath dataPath =
296 topoRouteService.getTopoShortestPath(srcSwitchPort,
297 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000298 if (dataPath == null) {
299 // We need the DataPath to compare the paths
300 dataPath = new DataPath();
301 dataPath.setSrcPort(srcSwitchPort);
302 dataPath.setDstPort(dstSwitchPort);
303 }
304
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700305 String newDataPathSummaryStr = dataPath.dataPathSummary();
306 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
307 continue; // Nothing changed
308
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700309 log.debug("RECONCILE: Need to Reconcile Shortest Path for FlowID {}",
310 flowId.toString());
311 flowObjSet.add(flowPathObj);
312 }
Pavlin Radoslavov53a3a8c2013-04-04 04:34:50 -0700313 log.debug("MEASUREMENT: Found {} Flows to reconcile",
Pavlin Radoslavove87f94e2013-04-04 04:31:09 -0700314 flowObjSet.size());
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700315 reconcileFlows(flowObjSet);
316 topoRouteService.dropShortestPathTopo();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700317
318
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800319 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700320
321 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700322 long estimatedTime =
323 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700324 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
325 (double)estimatedTime / 1000000000 + " sec";
326 log.debug(logMsg);
327 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700328
329 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700330 double rate = 0.0;
331 if (estimatedTime > 0)
332 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
333 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
334 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
335 counterMyNotUpdatedFlowEntries + " AllFlowPaths: " +
336 counterAllFlowPaths + " MyFlowPaths: " +
337 counterMyFlowPaths + " in " +
338 (double)estimatedTime / 1000000000 + " sec: " +
339 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700340 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800341 }
342 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700343
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700344 final ScheduledFuture<?> mapReaderHandle =
345 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800346
347 @Override
348 public void init(String conf) {
349 conn = GraphDBConnection.getInstance(conf);
350 }
351
352 public void finalize() {
353 close();
354 }
355
356 @Override
357 public void close() {
358 conn.close();
359 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800360
361 @Override
362 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
363 Collection<Class<? extends IFloodlightService>> l =
364 new ArrayList<Class<? extends IFloodlightService>>();
365 l.add(IFlowService.class);
366 return l;
367 }
368
369 @Override
370 public Map<Class<? extends IFloodlightService>, IFloodlightService>
371 getServiceImpls() {
372 Map<Class<? extends IFloodlightService>,
373 IFloodlightService> m =
374 new HashMap<Class<? extends IFloodlightService>,
375 IFloodlightService>();
376 m.put(IFlowService.class, this);
377 return m;
378 }
379
380 @Override
381 public Collection<Class<? extends IFloodlightService>>
382 getModuleDependencies() {
383 Collection<Class<? extends IFloodlightService>> l =
384 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800385 l.add(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700386 l.add(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800387 l.add(IRestApiService.class);
388 return l;
389 }
390
391 @Override
392 public void init(FloodlightModuleContext context)
393 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700394 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800395 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -0700396 topoRouteService = context.getServiceImpl(ITopoRouteService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800397 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800398 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
399 EnumSet.of(OFType.FLOW_MOD),
400 OFMESSAGE_DAMPER_TIMEOUT);
401 // TODO: An ugly hack!
402 String conf = "/tmp/cassandra.titan";
403 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800404 }
405
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000406 private long getNextFlowEntryId() {
407 //
408 // Generate the next Flow Entry ID.
409 // NOTE: For now, the higher 32 bits are random, and
410 // the lower 32 bits are sequential.
411 // In the future, we need a better allocation mechanism.
412 //
413 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
414 nextFlowEntryIdPrefix = randomGenerator.nextInt();
415 nextFlowEntryIdSuffix = 0;
416 } else {
417 nextFlowEntryIdSuffix++;
418 }
419 long result = (long)nextFlowEntryIdPrefix << 32;
420 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
421 return result;
422 }
423
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800424 @Override
425 public void startUp(FloodlightModuleContext context) {
426 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700427
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000428 // Initialize the Flow Entry ID generator
429 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800430 }
431
432 /**
433 * Add a flow.
434 *
435 * Internally, ONOS will automatically register the installer for
436 * receiving Flow Path Notifications for that path.
437 *
438 * @param flowPath the Flow Path to install.
439 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700440 * @param dataPathSummaryStr the data path summary string if the added
441 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800442 * @return true on success, otherwise false.
443 */
444 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700445 public boolean addFlow(FlowPath flowPath, FlowId flowId,
446 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700447 /*
448 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700449 if (flowPath.flowId().value() == measurementFlowId) {
450 modifiedMeasurementFlowTime = System.nanoTime();
451 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700452 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800453
454 //
455 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700456 // Right now every new flow entry gets a new flow entry ID
457 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800458 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800459 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000460 long id = getNextFlowEntryId();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800461 flowEntry.setFlowEntryId(new FlowEntryId(id));
462 }
463
464 IFlowPath flowObj = null;
465 try {
466 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
467 != null) {
468 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
469 flowPath.flowId().toString());
470 } else {
471 flowObj = conn.utils().newFlowPath(conn);
472 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
473 flowPath.flowId().toString());
474 }
475 } catch (Exception e) {
476 // TODO: handle exceptions
477 conn.endTx(Transaction.ROLLBACK);
478 log.error(":addFlow FlowId:{} failed",
479 flowPath.flowId().toString());
480 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700481 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000482 log.error(":addFlow FlowId:{} failed: Flow object not created",
483 flowPath.flowId().toString());
484 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800485 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700486 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800487
488 //
489 // Set the Flow key:
490 // - flowId
491 //
492 flowObj.setFlowId(flowPath.flowId().toString());
493 flowObj.setType("flow");
494
495 //
496 // Set the Flow attributes:
497 // - flowPath.installerId()
498 // - flowPath.dataPath().srcPort()
499 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700500 // - flowPath.matchEthernetFrameType()
501 // - flowPath.matchSrcIPv4Net()
502 // - flowPath.matchDstIPv4Net()
503 // - flowPath.matchSrcMac()
504 // - flowPath.matchDstMac()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800505 //
506 flowObj.setInstallerId(flowPath.installerId().toString());
507 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
508 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
509 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
510 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700511 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
512 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
513 }
514 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
515 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
516 }
517 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
518 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
519 }
520 if (flowPath.flowEntryMatch().matchSrcMac()) {
521 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
522 }
523 if (flowPath.flowEntryMatch().matchDstMac()) {
524 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
525 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800526
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700527 if (dataPathSummaryStr != null) {
528 flowObj.setDataPathSummary(dataPathSummaryStr);
529 } else {
530 flowObj.setDataPathSummary("");
531 }
532
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800533 // Flow edges:
534 // HeadFE
535
536
537 //
538 // Flow Entries:
539 // flowPath.dataPath().flowEntries()
540 //
541 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
542 IFlowEntry flowEntryObj = null;
543 boolean found = false;
544 try {
545 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
546 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
547 flowEntry.flowEntryId().toString());
548 found = true;
549 } else {
550 flowEntryObj = conn.utils().newFlowEntry(conn);
551 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
552 flowEntry.flowEntryId().toString());
553 }
554 } catch (Exception e) {
555 // TODO: handle exceptions
556 conn.endTx(Transaction.ROLLBACK);
557 log.error(":addFlow FlowEntryId:{} failed",
558 flowEntry.flowEntryId().toString());
559 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700560 if (flowEntryObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000561 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
562 flowEntry.flowEntryId().toString());
563 conn.endTx(Transaction.ROLLBACK);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800564 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700565 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800566
567 //
568 // Set the Flow Entry key:
569 // - flowEntry.flowEntryId()
570 //
571 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
572 flowEntryObj.setType("flow_entry");
573
574 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700575 // Set the Flow Entry Edges and attributes:
576 // - Switch edge
577 // - InPort edge
578 // - OutPort edge
579 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800580 // - flowEntry.flowEntryMatch()
581 // - flowEntry.flowEntryActions()
582 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800583 // - flowEntry.flowEntryUserState()
584 // - flowEntry.flowEntrySwitchState()
585 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700586 // - flowEntry.matchInPort()
587 // - flowEntry.matchEthernetFrameType()
588 // - flowEntry.matchSrcIPv4Net()
589 // - flowEntry.matchDstIPv4Net()
590 // - flowEntry.matchSrcMac()
591 // - flowEntry.matchDstMac()
592 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800593 //
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700594 ISwitchObject sw =
595 conn.utils().searchSwitch(conn, flowEntry.dpid().toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800596 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pankaj Berded0079742013-03-27 17:53:25 -0700597 flowEntryObj.setSwitch(sw);
598 if (flowEntry.flowEntryMatch().matchInPort()) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700599 IPortObject inport =
600 conn.utils().searchPort(conn, flowEntry.dpid().toString(),
601 flowEntry.flowEntryMatch().inPort().value());
Pankaj Berded0079742013-03-27 17:53:25 -0700602 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
603 flowEntryObj.setInPort(inport);
604 }
605 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
606 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
607 }
608 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
609 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
610 }
611 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
612 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
613 }
614 if (flowEntry.flowEntryMatch().matchSrcMac()) {
615 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
616 }
617 if (flowEntry.flowEntryMatch().matchDstMac()) {
618 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
619 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700620
621 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
Pankaj Berded0079742013-03-27 17:53:25 -0700622 if (fa.actionOutput() != null) {
Pavlin Radoslavovb6d1e362013-03-28 03:15:41 -0700623 IPortObject outport =
624 conn.utils().searchPort(conn,
625 flowEntry.dpid().toString(),
626 fa.actionOutput().port().value());
627 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
628 flowEntryObj.setOutPort(outport);
Pankaj Berded0079742013-03-27 17:53:25 -0700629 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700630 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800631 // TODO: Hacks with hard-coded state names!
632 if (found)
633 flowEntryObj.setUserState("FE_USER_MODIFY");
634 else
635 flowEntryObj.setUserState("FE_USER_ADD");
636 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
637 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700638 // TODO: Take care of the FlowEntryErrorState.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800639 //
640
641 // Flow Entries edges:
642 // Flow
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700643 // NextFE (TODO)
644 if (! found) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800645 flowObj.addFlowEntry(flowEntryObj);
Pavlin Radoslavove0575292013-03-28 05:35:25 -0700646 flowEntryObj.setFlow(flowObj);
647 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800648 }
649 conn.endTx(Transaction.COMMIT);
650
651 //
652 // TODO: We need a proper Flow ID allocation mechanism.
653 //
654 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700655
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800656 return true;
657 }
658
659 /**
660 * Delete a previously added flow.
661 *
662 * @param flowId the Flow ID of the flow to delete.
663 * @return true on success, otherwise false.
664 */
665 @Override
666 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700667 /*
668 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700669 if (flowId.value() == measurementFlowId) {
670 modifiedMeasurementFlowTime = System.nanoTime();
671 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700672 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700673
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800674 IFlowPath flowObj = null;
675 //
676 // We just mark the entries for deletion,
677 // and let the switches remove each individual entry after
678 // it has been removed from the switches.
679 //
680 try {
681 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
682 != null) {
683 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
684 flowId.toString());
685 } else {
686 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
687 flowId.toString());
688 }
689 } catch (Exception e) {
690 // TODO: handle exceptions
691 conn.endTx(Transaction.ROLLBACK);
692 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
693 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700694 if (flowObj == null) {
695 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800696 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700697 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800698
699 //
700 // Find and mark for deletion all Flow Entries
701 //
702 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
703 boolean empty = true; // TODO: an ugly hack
704 for (IFlowEntry flowEntryObj : flowEntries) {
705 empty = false;
706 // flowObj.removeFlowEntry(flowEntryObj);
707 // conn.utils().removeFlowEntry(conn, flowEntryObj);
708 flowEntryObj.setUserState("FE_USER_DELETE");
709 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
710 }
711 // Remove from the database empty flows
712 if (empty)
713 conn.utils().removeFlowPath(conn, flowObj);
714 conn.endTx(Transaction.COMMIT);
715
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800716 return true;
717 }
718
719 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700720 * Clear the state for a previously added flow.
721 *
722 * @param flowId the Flow ID of the flow to clear.
723 * @return true on success, otherwise false.
724 */
725 @Override
726 public boolean clearFlow(FlowId flowId) {
727 IFlowPath flowObj = null;
728 try {
729 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
730 != null) {
731 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
732 flowId.toString());
733 } else {
734 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
735 flowId.toString());
736 }
737 } catch (Exception e) {
738 // TODO: handle exceptions
739 conn.endTx(Transaction.ROLLBACK);
740 log.error(":clearFlow FlowId:{} failed", flowId.toString());
741 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700742 if (flowObj == null) {
743 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700744 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700745 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700746
747 //
748 // Remove all Flow Entries
749 //
750 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
751 for (IFlowEntry flowEntryObj : flowEntries) {
752 flowObj.removeFlowEntry(flowEntryObj);
753 conn.utils().removeFlowEntry(conn, flowEntryObj);
754 }
755 // Remove the Flow itself
756 conn.utils().removeFlowPath(conn, flowObj);
757 conn.endTx(Transaction.COMMIT);
758
759 return true;
760 }
761
762 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800763 * Get a previously added flow.
764 *
765 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800766 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800767 */
768 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800769 public FlowPath getFlow(FlowId flowId) {
770 IFlowPath flowObj = null;
771 try {
772 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
773 != null) {
774 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
775 flowId.toString());
776 } else {
777 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
778 flowId.toString());
779 }
780 } catch (Exception e) {
781 // TODO: handle exceptions
782 conn.endTx(Transaction.ROLLBACK);
783 log.error(":getFlow FlowId:{} failed", flowId.toString());
784 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700785 if (flowObj == null) {
786 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800787 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700788 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800789
790 //
791 // Extract the Flow state
792 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800793 FlowPath flowPath = extractFlowPath(flowObj);
794 conn.endTx(Transaction.COMMIT);
795
796 return flowPath;
797 }
798
799 /**
800 * Get all previously added flows by a specific installer for a given
801 * data path endpoints.
802 *
803 * @param installerId the Caller ID of the installer of the flow to get.
804 * @param dataPathEndpoints the data path endpoints of the flow to get.
805 * @return the Flow Paths if found, otherwise null.
806 */
807 @Override
808 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
809 DataPathEndpoints dataPathEndpoints) {
810 //
811 // TODO: The implementation below is not optimal:
812 // We fetch all flows, and then return only the subset that match
813 // the query conditions.
814 // We should use the appropriate Titan/Gremlin query to filter-out
815 // the flows as appropriate.
816 //
817 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700818 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800819
820 if (allFlows == null) {
821 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700822 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800823 }
824
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800825 for (FlowPath flow : allFlows) {
826 //
827 // TODO: String-based comparison is sub-optimal.
828 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800829 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800830 //
831 if (! flow.installerId().toString().equals(installerId.toString()))
832 continue;
833 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
834 continue;
835 }
836 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
837 continue;
838 }
839 flowPaths.add(flow);
840 }
841
842 if (flowPaths.isEmpty()) {
843 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800844 } else {
845 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
846 }
847
848 return flowPaths;
849 }
850
851 /**
852 * Get all installed flows by all installers for given data path endpoints.
853 *
854 * @param dataPathEndpoints the data path endpoints of the flows to get.
855 * @return the Flow Paths if found, otherwise null.
856 */
857 @Override
858 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
859 //
860 // TODO: The implementation below is not optimal:
861 // We fetch all flows, and then return only the subset that match
862 // the query conditions.
863 // We should use the appropriate Titan/Gremlin query to filter-out
864 // the flows as appropriate.
865 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700866 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
867 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800868
869 if (allFlows == null) {
870 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700871 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800872 }
873
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800874 for (FlowPath flow : allFlows) {
875 //
876 // TODO: String-based comparison is sub-optimal.
877 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800878 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800879 //
880 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
881 continue;
882 }
883 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
884 continue;
885 }
886 flowPaths.add(flow);
887 }
888
889 if (flowPaths.isEmpty()) {
890 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800891 } else {
892 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
893 }
894
895 return flowPaths;
896 }
897
898 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700899 * Get summary of all installed flows by all installers in a given range
900 *
901 * @param flowId the data path endpoints of the flows to get.
902 * @param maxFlows: the maximum number of flows to be returned
903 * @return the Flow Paths if found, otherwise null.
904 */
905 @Override
906 public ArrayList<FlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
907 //
908 // TODO: The implementation below is not optimal:
909 // We fetch all flows, and then return only the subset that match
910 // the query conditions.
911 // We should use the appropriate Titan/Gremlin query to filter-out
912 // the flows as appropriate.
913 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700914 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
915
916 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700917
918 if (allFlows == null) {
919 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700920 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700921 }
922
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -0700923 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700924
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700925 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700926 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700927
928 // start from desired flowId
Umesh Krishnaswamy2a82c642013-03-29 08:27:17 -0700929 //if (flow.flowId().value() < flowId.value()) {
930 // continue;
931 //}
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700932
933 // Summarize by making null flow entry fields that are not relevant to report
934 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
935 flowEntry.setFlowEntryActions(null);
936 flowEntry.setFlowEntryMatch(null);
937 }
938
939 flowPaths.add(flow);
940 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
941 break;
942 }
943 }
944
945 if (flowPaths.isEmpty()) {
946 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -0700947 } else {
948 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
949 }
950
951 return flowPaths;
952 }
953
954 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800955 * Get all installed flows by all installers.
956 *
957 * @return the Flow Paths if found, otherwise null.
958 */
959 @Override
960 public ArrayList<FlowPath> getAllFlows() {
961 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700962 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800963
964 try {
965 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
966 log.debug("Get all FlowPaths: found FlowPaths");
967 } else {
968 log.debug("Get all FlowPaths: no FlowPaths found");
969 }
970 } catch (Exception e) {
971 // TODO: handle exceptions
972 conn.endTx(Transaction.ROLLBACK);
973 log.error(":getAllFlowPaths failed");
974 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700975 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
976 conn.endTx(Transaction.COMMIT);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -0700977 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700978 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800979
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800980 for (IFlowPath flowObj : flowPathsObj) {
981 //
982 // Extract the Flow state
983 //
984 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -0700985 if (flowPath != null)
986 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800987 }
988
989 conn.endTx(Transaction.COMMIT);
990
991 return flowPaths;
992 }
993
994 /**
995 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
996 *
997 * @param flowObj the object to extract the Flow Path State from.
998 * @return the extracted Flow Path State.
999 */
1000 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001001 //
1002 // Extract the Flow state
1003 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001004 String flowIdStr = flowObj.getFlowId();
1005 String installerIdStr = flowObj.getInstallerId();
1006 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001007 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001008 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001009 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001010
1011 if ((flowIdStr == null) ||
1012 (installerIdStr == null) ||
1013 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001014 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001015 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001016 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001017 // TODO: A work-around, becauuse of some bogus database objects
1018 return null;
1019 }
1020
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001021 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001022 flowPath.setFlowId(new FlowId(flowIdStr));
1023 flowPath.setInstallerId(new CallerId(installerIdStr));
1024 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001025 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001026 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001027 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001028 //
1029 // Extract the match conditions common for all Flow Entries
1030 //
1031 {
1032 FlowEntryMatch match = new FlowEntryMatch();
1033 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1034 if (matchEthernetFrameType != null)
1035 match.enableEthernetFrameType(matchEthernetFrameType);
1036 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1037 if (matchSrcIPv4Net != null)
1038 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1039 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1040 if (matchDstIPv4Net != null)
1041 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1042 String matchSrcMac = flowObj.getMatchSrcMac();
1043 if (matchSrcMac != null)
1044 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1045 String matchDstMac = flowObj.getMatchDstMac();
1046 if (matchDstMac != null)
1047 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1048 flowPath.setFlowEntryMatch(match);
1049 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001050
1051 //
1052 // Extract all Flow Entries
1053 //
1054 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1055 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001056 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1057 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001058 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001059 flowPath.dataPath().flowEntries().add(flowEntry);
1060 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001061
1062 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001063 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001064
1065 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001066 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1067 *
1068 * @param flowEntryObj the object to extract the Flow Entry State from.
1069 * @return the extracted Flow Entry State.
1070 */
1071 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1072 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1073 String switchDpidStr = flowEntryObj.getSwitchDpid();
1074 String userState = flowEntryObj.getUserState();
1075 String switchState = flowEntryObj.getSwitchState();
1076
1077 if ((flowEntryIdStr == null) ||
1078 (switchDpidStr == null) ||
1079 (userState == null) ||
1080 (switchState == null)) {
1081 // TODO: A work-around, becauuse of some bogus database objects
1082 return null;
1083 }
1084
1085 FlowEntry flowEntry = new FlowEntry();
1086 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1087 flowEntry.setDpid(new Dpid(switchDpidStr));
1088
1089 //
1090 // Extract the match conditions
1091 //
1092 FlowEntryMatch match = new FlowEntryMatch();
1093 Short matchInPort = flowEntryObj.getMatchInPort();
1094 if (matchInPort != null)
1095 match.enableInPort(new Port(matchInPort));
1096 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1097 if (matchEthernetFrameType != null)
1098 match.enableEthernetFrameType(matchEthernetFrameType);
1099 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1100 if (matchSrcIPv4Net != null)
1101 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1102 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1103 if (matchDstIPv4Net != null)
1104 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1105 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1106 if (matchSrcMac != null)
1107 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1108 String matchDstMac = flowEntryObj.getMatchDstMac();
1109 if (matchDstMac != null)
1110 match.enableDstMac(MACAddress.valueOf(matchDstMac));
1111 flowEntry.setFlowEntryMatch(match);
1112
1113 //
1114 // Extract the actions
1115 //
1116 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
1117 Short actionOutputPort = flowEntryObj.getActionOutput();
1118 if (actionOutputPort != null) {
1119 FlowEntryAction action = new FlowEntryAction();
1120 action.setActionOutput(new Port(actionOutputPort));
1121 actions.add(action);
1122 }
1123 flowEntry.setFlowEntryActions(actions);
1124 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1125 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1126 //
1127 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
1128 // and FlowEntryErrorState.
1129 //
1130 return flowEntry;
1131 }
1132
1133 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001134 * Add and maintain a shortest-path flow.
1135 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001136 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001137 *
1138 * @param flowPath the Flow Path with the endpoints and the match
1139 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001140 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001141 */
1142 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001143 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001144 String dataPathSummaryStr = null;
1145
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001146 //
1147 // Do the shortest path computation
1148 //
1149 DataPath dataPath =
1150 topoRouteService.getShortestPath(flowPath.dataPath().srcPort(),
1151 flowPath.dataPath().dstPort());
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001152 if (dataPath == null) {
1153 // We need the DataPath to populate the Network MAP
1154 dataPath = new DataPath();
1155 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1156 dataPath.setDstPort(flowPath.dataPath().dstPort());
1157 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001158
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001159 // Compute the Data Path summary
1160 dataPathSummaryStr = dataPath.dataPathSummary();
1161
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001162 //
1163 // Set the incoming port matching and the outgoing port output
1164 // actions for each flow entry.
1165 //
1166 for (FlowEntry flowEntry : dataPath.flowEntries()) {
1167 // Set the incoming port matching
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001168 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001169 flowEntry.setFlowEntryMatch(flowEntryMatch);
1170 flowEntryMatch.enableInPort(flowEntry.inPort());
1171
1172 // Set the outgoing port output action
1173 ArrayList<FlowEntryAction> flowEntryActions = flowEntry.flowEntryActions();
1174 if (flowEntryActions == null) {
1175 flowEntryActions = new ArrayList<FlowEntryAction>();
1176 flowEntry.setFlowEntryActions(flowEntryActions);
1177 }
1178 FlowEntryAction flowEntryAction = new FlowEntryAction();
1179 flowEntryAction.setActionOutput(flowEntry.outPort());
1180 flowEntryActions.add(flowEntryAction);
1181 }
1182
1183 //
1184 // Prepare the computed Flow Path
1185 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001186 FlowPath computedFlowPath = new FlowPath();
1187 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1188 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
1189 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001190 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001191
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001192 FlowId flowId = new FlowId();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001193 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001194 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001195
1196 // TODO: Mark the flow for maintenance purpose
1197
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001198 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001199 }
1200
1201 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001202 * Reconcile all flows in a set.
1203 *
1204 * @param flowObjSet the set of flows that need to be reconciliated.
1205 */
1206 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1207 if (! flowObjSet.iterator().hasNext())
1208 return;
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001209
1210 //
1211 // Remove the old Flow Entries, and add the new Flow Entries
1212 //
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001213
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001214 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001215 LinkedList<FlowPath> flowPaths = new LinkedList<FlowPath>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001216 for (IFlowPath flowObj : flowObjSet) {
1217 FlowPath flowPath = extractFlowPath(flowObj);
1218 if (flowPath == null)
1219 continue;
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001220 flowPaths.add(flowPath);
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001221
1222 //
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001223 // Remove the Flow Entries from the Network MAP
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001224 //
1225 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001226 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001227 for (IFlowEntry flowEntryObj : flowEntries) {
1228 String dpidStr = flowEntryObj.getSwitchDpid();
1229 if (dpidStr == null)
1230 continue;
1231 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001232 /*
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001233 IOFSwitch mySwitch = mySwitches.get(dpid.value());
1234 if (mySwitch == null)
1235 continue; // Ignore the entry: not my switch
Pavlin Radoslavovb2b6d4f2013-04-01 21:27:31 +00001236 */
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001237 deleteFlowEntries.add(flowEntryObj);
1238 }
1239 for (IFlowEntry flowEntryObj : deleteFlowEntries) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001240 flowObj.removeFlowEntry(flowEntryObj);
1241 conn.utils().removeFlowEntry(conn, flowEntryObj);
1242 }
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001243 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001244
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001245 for (FlowPath flowPath : flowPaths) {
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001246 //
1247 // Delete the flow entries from the switches
1248 //
1249 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
1250 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_DELETE);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001251 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1252 if (mySwitch == null) {
1253 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001254 installRemoteFlowEntry(flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001255 } else {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001256 installFlowEntry(mySwitch, flowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001257 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001258 }
1259
1260 //
1261 // Calculate the new shortest path and install it in the
1262 // Network MAP.
1263 //
1264 FlowPath addedFlowPath = addAndMaintainShortestPathFlow(flowPath);
1265 if (addedFlowPath == null) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001266 log.error("Cannot add Shortest Path Flow from {} to {}: path not found?",
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001267 flowPath.dataPath().srcPort().toString(),
1268 flowPath.dataPath().dstPort().toString());
1269 continue;
1270 }
1271
1272 //
1273 // Add the flow entries to the switches
1274 //
1275 for (FlowEntry flowEntry : addedFlowPath.dataPath().flowEntries()) {
1276 flowEntry.setFlowEntryUserState(FlowEntryUserState.FE_USER_ADD);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001277 IOFSwitch mySwitch = mySwitches.get(flowEntry.dpid().value());
1278 if (mySwitch == null) {
1279 // Not my switch
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001280 installRemoteFlowEntry(addedFlowPath, flowEntry);
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001281 continue;
1282 }
1283
1284 IFlowEntry flowEntryObj =
1285 conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId());
1286 if (flowEntryObj == null) {
1287 //
1288 // TODO: Remove the "new Object[] wrapper in the statement
1289 // below after the SLF4J logger is upgraded to
1290 // Version 1.7.5
1291 //
1292 log.error("Cannot add Flow Entry to switch {} for Path Flow from {} to {} : Flow Entry not in the Network MAP",
1293 new Object[] {
1294 flowEntry.dpid(),
1295 flowPath.dataPath().srcPort(),
1296 flowPath.dataPath().dstPort()
1297 });
1298 continue;
1299 }
1300 // Update the Flow Entry Switch State in the Network MAP
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001301 if (installFlowEntry(mySwitch, addedFlowPath, flowEntry)) {
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001302 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1303 }
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001304 }
1305 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001306 }
1307
1308 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001309 * Install a Flow Entry on a switch.
1310 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001311 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001312 * @param flowObj the flow path object for the flow entry to install.
1313 * @param flowEntryObj the flow entry object to install.
1314 * @return true on success, otherwise false.
1315 */
1316 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1317 IFlowEntry flowEntryObj) {
1318 FlowEntryId flowEntryId =
1319 new FlowEntryId(flowEntryObj.getFlowEntryId());
1320 String userState = flowEntryObj.getUserState();
1321 String switchState = flowEntryObj.getSwitchState();
1322
1323 //
1324 // Create the Open Flow Flow Modification Entry to push
1325 //
1326 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1327 .getMessage(OFType.FLOW_MOD);
1328 long cookie = flowEntryId.value();
1329
1330 short flowModCommand = OFFlowMod.OFPFC_ADD;
1331 if (userState.equals("FE_USER_ADD")) {
1332 flowModCommand = OFFlowMod.OFPFC_ADD;
1333 } else if (userState.equals("FE_USER_MODIFY")) {
1334 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1335 } else if (userState.equals("FE_USER_DELETE")) {
1336 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1337 } else {
1338 // Unknown user state. Ignore the entry
1339 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1340 flowEntryId.toString(), userState);
1341 return false;
1342 }
1343
1344 //
1345 // Fetch the match conditions.
1346 //
1347 // NOTE: The Flow matching conditions common for all
1348 // Flow Entries are used ONLY if a Flow Entry does NOT
1349 // have the corresponding matching condition set.
1350 //
1351 OFMatch match = new OFMatch();
1352 match.setWildcards(OFMatch.OFPFW_ALL);
1353 //
1354 Short matchInPort = flowEntryObj.getMatchInPort();
1355 if (matchInPort != null) {
1356 match.setInputPort(matchInPort);
1357 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1358 }
1359 //
1360 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1361 if (matchEthernetFrameType == null)
1362 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1363 if (matchEthernetFrameType != null) {
1364 match.setDataLayerType(matchEthernetFrameType);
1365 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1366 }
1367 //
1368 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1369 if (matchSrcIPv4Net == null)
1370 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1371 if (matchSrcIPv4Net != null) {
1372 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1373 }
1374 //
1375 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1376 if (matchDstIPv4Net == null)
1377 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1378 if (matchDstIPv4Net != null) {
1379 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1380 }
1381 //
1382 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1383 if (matchSrcMac == null)
1384 matchSrcMac = flowObj.getMatchSrcMac();
1385 if (matchSrcMac != null) {
1386 match.setDataLayerSource(matchSrcMac);
1387 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1388 }
1389 //
1390 String matchDstMac = flowEntryObj.getMatchDstMac();
1391 if (matchDstMac == null)
1392 matchDstMac = flowObj.getMatchDstMac();
1393 if (matchDstMac != null) {
1394 match.setDataLayerDestination(matchDstMac);
1395 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1396 }
1397
1398 //
1399 // Fetch the actions
1400 //
1401 List<OFAction> actions = new ArrayList<OFAction>();
1402 Short actionOutputPort = flowEntryObj.getActionOutput();
1403 if (actionOutputPort != null) {
1404 OFActionOutput action = new OFActionOutput();
1405 // XXX: The max length is hard-coded for now
1406 action.setMaxLength((short)0xffff);
1407 action.setPort(actionOutputPort);
1408 actions.add(action);
1409 }
1410
1411 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1412 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1413 .setPriority(PRIORITY_DEFAULT)
1414 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1415 .setCookie(cookie)
1416 .setCommand(flowModCommand)
1417 .setMatch(match)
1418 .setActions(actions)
1419 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1420 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1421 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1422 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1423 if (actionOutputPort != null)
1424 fm.setOutPort(actionOutputPort);
1425 }
1426
1427 //
1428 // TODO: Set the following flag
1429 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1430 // See method ForwardingBase::pushRoute()
1431 //
1432 try {
1433 messageDamper.write(mySwitch, fm, null);
1434 mySwitch.flush();
1435 //
1436 // TODO: We should use the OpenFlow Barrier mechanism
1437 // to check for errors, and update the SwitchState
1438 // for a flow entry after the Barrier message is
1439 // is received.
1440 //
1441 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1442 } catch (IOException e) {
1443 log.error("Failure writing flow mod from network map", e);
1444 }
1445
1446 return true;
1447 }
1448
1449 /**
1450 * Install a Flow Entry on a switch.
1451 *
1452 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001453 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001454 * @param flowEntry the flow entry to install.
1455 * @return true on success, otherwise false.
1456 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001457 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1458 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001459 //
1460 // Create the OpenFlow Flow Modification Entry to push
1461 //
1462 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1463 .getMessage(OFType.FLOW_MOD);
1464 long cookie = flowEntry.flowEntryId().value();
1465
1466 short flowModCommand = OFFlowMod.OFPFC_ADD;
1467 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1468 flowModCommand = OFFlowMod.OFPFC_ADD;
1469 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1470 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1471 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1472 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1473 } else {
1474 // Unknown user state. Ignore the entry
1475 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1476 flowEntry.flowEntryId().toString(),
1477 flowEntry.flowEntryUserState());
1478 return false;
1479 }
1480
1481 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001482 // Fetch the match conditions.
1483 //
1484 // NOTE: The Flow matching conditions common for all Flow Entries are
1485 // used ONLY if a Flow Entry does NOT have the corresponding matching
1486 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001487 //
1488 OFMatch match = new OFMatch();
1489 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001490 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1491 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1492
1493 // Match the Incoming Port
1494 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001495 if (matchInPort != null) {
1496 match.setInputPort(matchInPort.value());
1497 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1498 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001499
1500 // Match the Ethernet Frame Type
1501 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
1502 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
1503 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
1504 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001505 if (matchEthernetFrameType != null) {
1506 match.setDataLayerType(matchEthernetFrameType);
1507 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1508 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001509
1510 // Match the Source IPv4 Network prefix
1511 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
1512 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
1513 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
1514 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001515 if (matchSrcIPv4Net != null) {
1516 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
1517 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001518
1519 // Natch the Destination IPv4 Network prefix
1520 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
1521 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
1522 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
1523 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001524 if (matchDstIPv4Net != null) {
1525 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
1526 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001527
1528 // Match the Source MAC address
1529 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1530 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1531 matchSrcMac = flowPathMatch.srcMac();
1532 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001533 if (matchSrcMac != null) {
1534 match.setDataLayerSource(matchSrcMac.toString());
1535 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1536 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001537
1538 // Match the Destination MAC address
1539 MACAddress matchDstMac = flowEntryMatch.dstMac();
1540 if ((matchDstMac == null) && (flowPathMatch != null)) {
1541 matchDstMac = flowPathMatch.dstMac();
1542 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001543 if (matchDstMac != null) {
1544 match.setDataLayerDestination(matchDstMac.toString());
1545 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1546 }
1547
1548 //
1549 // Fetch the actions
1550 //
1551 // TODO: For now we support only the "OUTPUT" actions.
1552 //
1553 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1554 List<OFAction> actions = new ArrayList<OFAction>();
1555 ArrayList<FlowEntryAction> flowEntryActions =
1556 flowEntry.flowEntryActions();
1557 for (FlowEntryAction flowEntryAction : flowEntryActions) {
1558 FlowEntryAction.ActionOutput actionOutput =
1559 flowEntryAction.actionOutput();
1560 if (actionOutput != null) {
1561 short actionOutputPort = actionOutput.port().value();
1562 OFActionOutput action = new OFActionOutput();
1563 // XXX: The max length is hard-coded for now
1564 action.setMaxLength((short)0xffff);
1565 action.setPort(actionOutputPort);
1566 actions.add(action);
1567 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1568 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1569 fm.setOutPort(actionOutputPort);
1570 }
1571 }
1572 }
1573
1574 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1575 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1576 .setPriority(PRIORITY_DEFAULT)
1577 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1578 .setCookie(cookie)
1579 .setCommand(flowModCommand)
1580 .setMatch(match)
1581 .setActions(actions)
1582 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
1583
1584 //
1585 // TODO: Set the following flag
1586 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1587 // See method ForwardingBase::pushRoute()
1588 //
1589
1590 //
1591 // Write the message to the switch
1592 //
1593 try {
1594 messageDamper.write(mySwitch, fm, null);
1595 mySwitch.flush();
1596 } catch (IOException e) {
1597 log.error("Failure writing flow mod from network map", e);
1598 return false;
1599 }
1600 return true;
1601 }
1602
1603 /**
1604 * Remove a Flow Entry from a switch.
1605 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001606 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001607 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001608 * @param flowEntry the flow entry to remove.
1609 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001610 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001611 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1612 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001613 //
1614 // The installFlowEntry() method implements both installation
1615 // and removal of flow entries.
1616 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001617 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001618 }
1619
1620 /**
1621 * Install a Flow Entry on a remote controller.
1622 *
1623 * TODO: We need it now: Jono
1624 * - For now it will make a REST call to the remote controller.
1625 * - Internally, it needs to know the name of the remote controller.
1626 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001627 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001628 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001629 * @return true on success, otherwise false.
1630 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001631 public boolean installRemoteFlowEntry(FlowPath flowPath,
1632 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001633 // TODO: We need it now: Jono
1634 // - For now it will make a REST call to the remote controller.
1635 // - Internally, it needs to know the name of the remote controller.
1636 return true;
1637 }
1638
1639 /**
1640 * Remove a flow entry on a remote controller.
1641 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001642 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001643 * @param flowEntry the flow entry to remove.
1644 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001645 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001646 public boolean removeRemoteFlowEntry(FlowPath flowPath,
1647 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07001648 //
1649 // The installRemoteFlowEntry() method implements both installation
1650 // and removal of flow entries.
1651 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001652 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001653 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001654}