blob: bca9ef76a99b99f8bc89c78e102984f52f62d4cf [file] [log] [blame]
HIGUCHI Yuta60a10142013-06-14 15:50:10 -07001package net.onrc.onos.ofcontroller.flowmanager;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00004import java.io.PrintWriter;
5import java.io.StringWriter;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08006import java.util.ArrayList;
7import java.util.Collection;
Jonathan Hartf5315fb2013-04-05 11:41:56 -07008import java.util.Collections;
9import java.util.Comparator;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080010import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080011import java.util.HashMap;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +000012import java.util.LinkedList;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080013import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080014import java.util.Map;
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000015import java.util.Random;
Pavlin Radoslavov759772f2013-05-20 20:50:00 +000016import java.util.concurrent.ConcurrentLinkedQueue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080017import java.util.concurrent.Executors;
18import java.util.concurrent.ScheduledExecutorService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080019import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080020
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IFloodlightProviderService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080022import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080023import net.floodlightcontroller.core.module.FloodlightModuleContext;
24import net.floodlightcontroller.core.module.FloodlightModuleException;
25import net.floodlightcontroller.core.module.IFloodlightModule;
26import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080027import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070028import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080029import net.floodlightcontroller.util.OFMessageDamper;
Pankaj Berde38646d62013-06-21 11:34:04 -070030import net.onrc.onos.graph.GraphDBOperation;
HIGUCHI Yuta20514902013-06-12 11:24:16 -070031import net.onrc.onos.ofcontroller.core.INetMapStorage;
32import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
33import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
34import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IPortObject;
35import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.ISwitchObject;
36import net.onrc.onos.ofcontroller.core.INetMapTopologyService.ITopoRouteService;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070037import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -070038import net.onrc.onos.ofcontroller.routing.TopoRouteService;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070039import net.onrc.onos.ofcontroller.util.CallerId;
40import net.onrc.onos.ofcontroller.util.DataPath;
41import net.onrc.onos.ofcontroller.util.DataPathEndpoints;
42import net.onrc.onos.ofcontroller.util.Dpid;
43import net.onrc.onos.ofcontroller.util.FlowEntry;
44import net.onrc.onos.ofcontroller.util.FlowEntryAction;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070045import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
46import net.onrc.onos.ofcontroller.util.FlowEntryActions;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070047import net.onrc.onos.ofcontroller.util.FlowEntryId;
48import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
49import net.onrc.onos.ofcontroller.util.FlowEntrySwitchState;
50import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
51import net.onrc.onos.ofcontroller.util.FlowId;
52import net.onrc.onos.ofcontroller.util.FlowPath;
Pavlin Radoslavov204b2862013-07-12 14:15:36 -070053import net.onrc.onos.ofcontroller.util.FlowPathFlags;
HIGUCHI Yuta356086e2013-06-12 15:21:19 -070054import net.onrc.onos.ofcontroller.util.IPv4Net;
55import net.onrc.onos.ofcontroller.util.Port;
56import net.onrc.onos.ofcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080057
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;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -070063import org.openflow.protocol.action.*;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080064import org.slf4j.Logger;
65import org.slf4j.LoggerFactory;
66
Jonathan Hartf5315fb2013-04-05 11:41:56 -070067
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070068public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080069
Toshio Koide9fe1cb22013-06-13 13:51:11 -070070 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080071
72 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070073 protected volatile IFloodlightProviderService floodlightProvider;
74 protected volatile ITopoRouteService topoRouteService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070075 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080076
77 protected OFMessageDamper messageDamper;
78
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070079 //
80 // TODO: Values copied from elsewhere (class LearningSwitch).
81 // The local copy should go away!
82 //
83 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
84 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
85 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
86 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
87 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080088
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000089 // Flow Entry ID generation state
90 private static Random randomGenerator = new Random();
91 private static int nextFlowEntryIdPrefix = 0;
92 private static int nextFlowEntryIdSuffix = 0;
93 private static long nextFlowEntryId = 0;
94
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070095 // State for measurement purpose
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 Radoslavov4ef543e2013-05-07 13:36:57 -070099 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700100
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800101 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800102 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
103
104 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700105 private ScheduledExecutorService mapReaderScheduler;
106 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700107
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700108 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800109 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700110 try {
111 runImpl();
112 } catch (Exception e) {
113 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700114 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700115 return;
116 }
117 }
118
119 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700120 long startTime = System.nanoTime();
121 int counterAllFlowEntries = 0;
122 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700123
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800124 if (floodlightProvider == null) {
125 log.debug("FloodlightProvider service not found!");
126 return;
127 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000128 Map<Long, IOFSwitch> mySwitches =
129 floodlightProvider.getSwitches();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700130 LinkedList<IFlowEntry> addFlowEntries =
131 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000132 LinkedList<IFlowEntry> deleteFlowEntries =
133 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700134
135 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700136 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700137 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700138 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700139 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000140 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700141 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700142 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700143 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000144
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000145 String dpidStr = flowEntryObj.getSwitchDpid();
146 if (dpidStr == null)
147 continue;
148 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800149 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000150 if (mySwitch == null)
151 continue; // Ignore the entry: not my switch
152
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700153 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700154 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700155 if (flowObj == null)
156 continue; // Should NOT happen
157 if (flowObj.getFlowId() == null)
158 continue; // Invalid entry
159
160 //
161 // NOTE: For now we process the DELETE before the ADD
162 // to cover the more common scenario.
163 // TODO: This is error prone and needs to be fixed!
164 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000165 String userState = flowEntryObj.getUserState();
166 if (userState == null)
167 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700168 if (userState.equals("FE_USER_DELETE")) {
169 // An entry that needs to be deleted.
170 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700171 installFlowEntry(mySwitch, flowObj, flowEntryObj);
172 } else {
173 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700174 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700175 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700176 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700177 // TODO: Commented-out for now
178 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700180 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700181 processed_measurement_flow = true;
182 }
183 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700184 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700185 }
186
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700187 //
188 // Process the Flow Entries that need to be added
189 //
190 for (IFlowEntry flowEntryObj : addFlowEntries) {
191 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700192 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700193 if (flowObj == null)
194 continue; // Should NOT happen
195 if (flowObj.getFlowId() == null)
196 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700197
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700198 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700199 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000200 if (mySwitch == null)
201 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700202 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800203 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204
205 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000206 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700207 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000208 //
209 // TODO: We should use the OpenFlow Barrier mechanism
210 // to check for errors, and delete the Flow Entries after the
211 // Barrier message is received.
212 //
213 while (! deleteFlowEntries.isEmpty()) {
214 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
215 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700216 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000217 if (flowObj == null) {
218 log.debug("Did not find FlowPath to be deleted");
219 continue;
220 }
221 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700222 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000223 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700224
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700225 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700226
227 if (processed_measurement_flow) {
228 long estimatedTime =
229 System.nanoTime() - modifiedMeasurementFlowTime;
230 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
231 (double)estimatedTime / 1000000000 + " sec";
232 log.debug(logMsg);
233 }
234
235 long estimatedTime = System.nanoTime() - startTime;
236 double rate = 0.0;
237 if (estimatedTime > 0)
238 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
239 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
240 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
241 counterMyNotUpdatedFlowEntries + " in " +
242 (double)estimatedTime / 1000000000 + " sec: " +
243 rate + " paths/s";
244 log.debug(logMsg);
245 }
246 };
247
248 final Runnable shortestPathReconcile = new Runnable() {
249 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700250 try {
251 runImpl();
252 } catch (Exception e) {
253 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700254 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700255 return;
256 }
257 }
258
259 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700260 long startTime = System.nanoTime();
261 int counterAllFlowPaths = 0;
262 int counterMyFlowPaths = 0;
263
264 if (floodlightProvider == null) {
265 log.debug("FloodlightProvider service not found!");
266 return;
267 }
268 Map<Long, IOFSwitch> mySwitches =
269 floodlightProvider.getSwitches();
270 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
271
272 boolean processed_measurement_flow = false;
273
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700274 //
275 // Fetch and recompute the Shortest Path for those
276 // Flow Paths this controller is responsible for.
277 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000278 Map<Long, ?> shortestPathTopo =
279 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700280 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700281 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700282 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700283 if (flowPathObj == null)
284 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700285
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700286 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000287 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700288 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700289 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700290 //
291 // Use the source DPID as a heuristic to decide
292 // which controller is responsible for maintaining the
293 // shortest path.
294 // NOTE: This heuristic is error-prone: if the switch
295 // goes away and no controller is responsible for that
296 // switch, then the original Flow Path is not cleaned-up
297 //
298 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
299 if (mySwitch == null)
300 continue; // Ignore: not my responsibility
301
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700302 // Test the Data Path Summary string
303 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
304 if (dataPathSummaryStr == null)
305 continue; // Could be invalid entry?
306 if (dataPathSummaryStr.isEmpty())
307 continue; // No need to maintain this flow
308
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000309 //
310 // Test whether we need to complete the Flow cleanup,
311 // if the Flow has been deleted by the user.
312 //
313 String flowUserState = flowPathObj.getUserState();
314 if ((flowUserState != null)
315 && flowUserState.equals("FE_USER_DELETE")) {
316 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
317 boolean empty = true; // TODO: an ugly hack
318 for (IFlowEntry flowEntryObj : flowEntries) {
319 empty = false;
320 break;
321 }
322 if (empty)
323 deleteFlows.add(flowPathObj);
324 }
325
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000326 // Fetch the fields needed to recompute the shortest path
327 Short srcPortShort = flowPathObj.getSrcPort();
328 String dstDpidStr = flowPathObj.getDstSwitch();
329 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700330 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000331 if ((srcPortShort == null) ||
332 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700333 (dstPortShort == null) ||
334 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000335 continue;
336 }
337
338 Port srcPort = new Port(srcPortShort);
339 Dpid dstDpid = new Dpid(dstDpidStr);
340 Port dstPort = new Port(dstPortShort);
341 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
342 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700343 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000344
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700345 counterMyFlowPaths++;
346
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700347 //
348 // NOTE: Using here the regular getShortestPath() method
349 // won't work here, because that method calls internally
350 // "conn.endTx(Transaction.COMMIT)", and that will
351 // invalidate all handlers to the Titan database.
352 // If we want to experiment with calling here
353 // getShortestPath(), we need to refactor that code
354 // to avoid closing the transaction.
355 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700356 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000357 topoRouteService.getTopoShortestPath(shortestPathTopo,
358 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700359 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000360 if (dataPath == null) {
361 // We need the DataPath to compare the paths
362 dataPath = new DataPath();
363 dataPath.setSrcPort(srcSwitchPort);
364 dataPath.setDstPort(dstSwitchPort);
365 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700366 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000367
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700368 String newDataPathSummaryStr = dataPath.dataPathSummary();
369 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
370 continue; // Nothing changed
371
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700372 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700373 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000374
375 //
376 // Delete all leftover Flows marked for deletion from the
377 // Network MAP.
378 //
379 while (! deleteFlows.isEmpty()) {
380 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700381 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000382 }
383
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000384 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700385
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700386 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700387
388 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700389 long estimatedTime =
390 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700391 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
392 (double)estimatedTime / 1000000000 + " sec";
393 log.debug(logMsg);
394 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700395
396 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700397 double rate = 0.0;
398 if (estimatedTime > 0)
399 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700400 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700401 counterAllFlowPaths + " MyFlowPaths: " +
402 counterMyFlowPaths + " in " +
403 (double)estimatedTime / 1000000000 + " sec: " +
404 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700405 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800406 }
407 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700408
Jonathan Hart50a94982013-04-10 14:49:51 -0700409 //final ScheduledFuture<?> mapReaderHandle =
410 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800411
Jonathan Hart50a94982013-04-10 14:49:51 -0700412 //final ScheduledFuture<?> shortestPathReconcileHandle =
413 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700414
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800415 @Override
416 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700417 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700418 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800419 }
420
421 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700422 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800423 }
424
425 @Override
426 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700427 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800429
430 @Override
431 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
432 Collection<Class<? extends IFloodlightService>> l =
433 new ArrayList<Class<? extends IFloodlightService>>();
434 l.add(IFlowService.class);
435 return l;
436 }
437
438 @Override
439 public Map<Class<? extends IFloodlightService>, IFloodlightService>
440 getServiceImpls() {
441 Map<Class<? extends IFloodlightService>,
442 IFloodlightService> m =
443 new HashMap<Class<? extends IFloodlightService>,
444 IFloodlightService>();
445 m.put(IFlowService.class, this);
446 return m;
447 }
448
449 @Override
450 public Collection<Class<? extends IFloodlightService>>
451 getModuleDependencies() {
452 Collection<Class<? extends IFloodlightService>> l =
453 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800454 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800455 l.add(IRestApiService.class);
456 return l;
457 }
458
459 @Override
460 public void init(FloodlightModuleContext context)
461 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700462 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800463 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800464 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800465 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
466 EnumSet.of(OFType.FLOW_MOD),
467 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700468
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800469 // TODO: An ugly hack!
470 String conf = "/tmp/cassandra.titan";
471 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700472
473 mapReaderScheduler = Executors.newScheduledThreadPool(1);
474 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800475 }
476
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700477 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000478 //
479 // Generate the next Flow Entry ID.
480 // NOTE: For now, the higher 32 bits are random, and
481 // the lower 32 bits are sequential.
482 // In the future, we need a better allocation mechanism.
483 //
484 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
485 nextFlowEntryIdPrefix = randomGenerator.nextInt();
486 nextFlowEntryIdSuffix = 0;
487 } else {
488 nextFlowEntryIdSuffix++;
489 }
490 long result = (long)nextFlowEntryIdPrefix << 32;
491 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
492 return result;
493 }
494
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800495 @Override
496 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700497 restApi.addRestletRoutable(new FlowWebRoutable());
498
499 // Initialize the Flow Entry ID generator
500 nextFlowEntryIdPrefix = randomGenerator.nextInt();
501
502 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200503 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700504 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200505 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800506 }
507
508 /**
509 * Add a flow.
510 *
511 * Internally, ONOS will automatically register the installer for
512 * receiving Flow Path Notifications for that path.
513 *
514 * @param flowPath the Flow Path to install.
515 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700516 * @param dataPathSummaryStr the data path summary string if the added
517 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800518 * @return true on success, otherwise false.
519 */
520 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700521 public boolean addFlow(FlowPath flowPath, FlowId flowId,
522 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700523 /*
524 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700525 if (flowPath.flowId().value() == measurementFlowId) {
526 modifiedMeasurementFlowTime = System.nanoTime();
527 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700528 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800529
530 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000531 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800532 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700533 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800534 != null) {
535 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
536 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000537 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800538 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700539 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800540 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
541 flowPath.flowId().toString());
542 }
543 } catch (Exception e) {
544 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700545 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000546
547 StringWriter sw = new StringWriter();
548 e.printStackTrace(new PrintWriter(sw));
549 String stacktrace = sw.toString();
550
551 log.error(":addFlow FlowId:{} failed: {}",
552 flowPath.flowId().toString(),
553 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800554 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700555 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000556 log.error(":addFlow FlowId:{} failed: Flow object not created",
557 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700558 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800559 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700560 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800561
562 //
563 // Set the Flow key:
564 // - flowId
565 //
566 flowObj.setFlowId(flowPath.flowId().toString());
567 flowObj.setType("flow");
568
569 //
570 // Set the Flow attributes:
571 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700572 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800573 // - flowPath.dataPath().srcPort()
574 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700575 // - flowPath.matchSrcMac()
576 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700577 // - flowPath.matchEthernetFrameType()
578 // - flowPath.matchVlanId()
579 // - flowPath.matchVlanPriority()
580 // - flowPath.matchSrcIPv4Net()
581 // - flowPath.matchDstIPv4Net()
582 // - flowPath.matchIpProto()
583 // - flowPath.matchIpToS()
584 // - flowPath.matchSrcTcpUdpPort()
585 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700586 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800587 //
588 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700589 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800590 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
591 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
592 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
593 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700594 if (flowPath.flowEntryMatch().matchSrcMac()) {
595 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
596 }
597 if (flowPath.flowEntryMatch().matchDstMac()) {
598 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
599 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700600 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
601 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
602 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700603 if (flowPath.flowEntryMatch().matchVlanId()) {
604 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
605 }
606 if (flowPath.flowEntryMatch().matchVlanPriority()) {
607 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
608 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700609 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
610 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
611 }
612 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
613 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
614 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700615 if (flowPath.flowEntryMatch().matchIpProto()) {
616 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700617 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700618 if (flowPath.flowEntryMatch().matchIpToS()) {
619 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
620 }
621 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
622 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
623 }
624 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
625 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700626 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700627 if (! flowPath.flowEntryActions().actions().isEmpty()) {
628 flowObj.setActions(flowPath.flowEntryActions().toString());
629 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800630
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700631 if (dataPathSummaryStr != null) {
632 flowObj.setDataPathSummary(dataPathSummaryStr);
633 } else {
634 flowObj.setDataPathSummary("");
635 }
636
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000637 if (found)
638 flowObj.setUserState("FE_USER_MODIFY");
639 else
640 flowObj.setUserState("FE_USER_ADD");
641
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800642 // Flow edges:
643 // HeadFE
644
645
646 //
647 // Flow Entries:
648 // flowPath.dataPath().flowEntries()
649 //
650 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700651 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700652 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800653 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700654 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800655 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700656 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800657
658 //
659 // TODO: We need a proper Flow ID allocation mechanism.
660 //
661 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700662
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800663 return true;
664 }
665
666 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700667 * Add a flow entry to the Network MAP.
668 *
669 * @param flowObj the corresponding Flow Path object for the Flow Entry.
670 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700671 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700672 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700673 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700674 // Flow edges
675 // HeadFE (TODO)
676
677 //
678 // Assign the FlowEntry ID.
679 //
680 if ((flowEntry.flowEntryId() == null) ||
681 (flowEntry.flowEntryId().value() == 0)) {
682 long id = getNextFlowEntryId();
683 flowEntry.setFlowEntryId(new FlowEntryId(id));
684 }
685
686 IFlowEntry flowEntryObj = null;
687 boolean found = false;
688 try {
689 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700690 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700691 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
692 flowEntry.flowEntryId().toString());
693 found = true;
694 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700695 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700696 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
697 flowEntry.flowEntryId().toString());
698 }
699 } catch (Exception e) {
700 log.error(":addFlow FlowEntryId:{} failed",
701 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700702 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700703 }
704 if (flowEntryObj == null) {
705 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
706 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700707 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700708 }
709
710 //
711 // Set the Flow Entry key:
712 // - flowEntry.flowEntryId()
713 //
714 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
715 flowEntryObj.setType("flow_entry");
716
717 //
718 // Set the Flow Entry Edges and attributes:
719 // - Switch edge
720 // - InPort edge
721 // - OutPort edge
722 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700723 // - flowEntry.dpid()
724 // - flowEntry.flowEntryUserState()
725 // - flowEntry.flowEntrySwitchState()
726 // - flowEntry.flowEntryErrorState()
727 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700728 // - flowEntry.matchSrcMac()
729 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700730 // - flowEntry.matchEthernetFrameType()
731 // - flowEntry.matchVlanId()
732 // - flowEntry.matchVlanPriority()
733 // - flowEntry.matchSrcIPv4Net()
734 // - flowEntry.matchDstIPv4Net()
735 // - flowEntry.matchIpProto()
736 // - flowEntry.matchIpToS()
737 // - flowEntry.matchSrcTcpUdpPort()
738 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700739 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700740 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700741 //
742 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700743 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700744 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
745 flowEntryObj.setSwitch(sw);
746 if (flowEntry.flowEntryMatch().matchInPort()) {
747 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700748 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700749 flowEntry.flowEntryMatch().inPort().value());
750 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
751 flowEntryObj.setInPort(inport);
752 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700753 if (flowEntry.flowEntryMatch().matchSrcMac()) {
754 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
755 }
756 if (flowEntry.flowEntryMatch().matchDstMac()) {
757 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
758 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700759 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
760 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
761 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700762 if (flowEntry.flowEntryMatch().matchVlanId()) {
763 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
764 }
765 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
766 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
767 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700768 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
769 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
770 }
771 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
772 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
773 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700774 if (flowEntry.flowEntryMatch().matchIpProto()) {
775 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700776 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700777 if (flowEntry.flowEntryMatch().matchIpToS()) {
778 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
779 }
780 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
781 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
782 }
783 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
784 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700785 }
786
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700787 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700788 if (fa.actionOutput() != null) {
789 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700790 op.searchPort(flowEntry.dpid().toString(),
791 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700792 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700793 flowEntryObj.setOutPort(outport);
794 }
795 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700796 if (! flowEntry.flowEntryActions().isEmpty()) {
797 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
798 }
799
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700800 // TODO: Hacks with hard-coded state names!
801 if (found)
802 flowEntryObj.setUserState("FE_USER_MODIFY");
803 else
804 flowEntryObj.setUserState("FE_USER_ADD");
805 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
806 //
807 // TODO: Take care of the FlowEntryErrorState.
808 //
809
810 // Flow Entries edges:
811 // Flow
812 // NextFE (TODO)
813 if (! found) {
814 flowObj.addFlowEntry(flowEntryObj);
815 flowEntryObj.setFlow(flowObj);
816 }
817
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700818 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700819 }
820
821 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000822 * Delete all previously added flows.
823 *
824 * @return true on success, otherwise false.
825 */
826 @Override
827 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000828 List<Thread> threads = new LinkedList<Thread>();
829 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
830 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000831
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000832 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700833 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000834 for (IFlowPath flowPathObj : allFlowPaths) {
835 if (flowPathObj == null)
836 continue;
837 String flowIdStr = flowPathObj.getFlowId();
838 if (flowIdStr == null)
839 continue;
840 FlowId flowId = new FlowId(flowIdStr);
841 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000842 }
843
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000844 // Delete all flows one-by-one
845 for (FlowId flowId : concurrentAllFlowIds)
846 deleteFlow(flowId);
847
848 /*
849 * TODO: A faster mechanism to delete the Flow Paths by using
850 * a number of threads. Commented-out for now.
851 */
852 /*
853 //
854 // Create the threads to delete the Flow Paths
855 //
856 for (int i = 0; i < 10; i++) {
857 Thread thread = new Thread(new Runnable() {
858 @Override
859 public void run() {
860 while (true) {
861 FlowId flowId = concurrentAllFlowIds.poll();
862 if (flowId == null)
863 return;
864 deleteFlow(flowId);
865 }
866 }}, "Delete All Flow Paths");
867 threads.add(thread);
868 }
869
870 // Start processing
871 for (Thread thread : threads) {
872 thread.start();
873 }
874
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000875 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000876 for (Thread thread : threads) {
877 try {
878 thread.join();
879 } catch (InterruptedException e) {
880 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
881 }
882 }
883 */
884
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000885 return true;
886 }
887
888 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800889 * Delete a previously added flow.
890 *
891 * @param flowId the Flow ID of the flow to delete.
892 * @return true on success, otherwise false.
893 */
894 @Override
895 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700896 /*
897 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700898 if (flowId.value() == measurementFlowId) {
899 modifiedMeasurementFlowTime = System.nanoTime();
900 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700901 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700902
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800903 IFlowPath flowObj = null;
904 //
905 // We just mark the entries for deletion,
906 // and let the switches remove each individual entry after
907 // it has been removed from the switches.
908 //
909 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700910 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800911 != null) {
912 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
913 flowId.toString());
914 } else {
915 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
916 flowId.toString());
917 }
918 } catch (Exception e) {
919 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700920 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800921 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
922 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700923 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700924 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800925 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700926 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800927
928 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000929 // Find and mark for deletion all Flow Entries,
930 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800931 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000932 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800933 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
934 boolean empty = true; // TODO: an ugly hack
935 for (IFlowEntry flowEntryObj : flowEntries) {
936 empty = false;
937 // flowObj.removeFlowEntry(flowEntryObj);
938 // conn.utils().removeFlowEntry(conn, flowEntryObj);
939 flowEntryObj.setUserState("FE_USER_DELETE");
940 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
941 }
942 // Remove from the database empty flows
943 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700944 op.removeFlowPath(flowObj);
945 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800946
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800947 return true;
948 }
949
950 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000951 * Clear the state for all previously added flows.
952 *
953 * @return true on success, otherwise false.
954 */
955 @Override
956 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000957 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000958
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000959 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700960 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000961 for (IFlowPath flowPathObj : allFlowPaths) {
962 if (flowPathObj == null)
963 continue;
964 String flowIdStr = flowPathObj.getFlowId();
965 if (flowIdStr == null)
966 continue;
967 FlowId flowId = new FlowId(flowIdStr);
968 allFlowIds.add(flowId);
969 }
970
971 // Clear all flows one-by-one
972 for (FlowId flowId : allFlowIds) {
973 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000974 }
975
976 return true;
977 }
978
979 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700980 * Clear the state for a previously added flow.
981 *
982 * @param flowId the Flow ID of the flow to clear.
983 * @return true on success, otherwise false.
984 */
985 @Override
986 public boolean clearFlow(FlowId flowId) {
987 IFlowPath flowObj = null;
988 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700989 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700990 != null) {
991 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
992 flowId.toString());
993 } else {
994 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
995 flowId.toString());
996 }
997 } catch (Exception e) {
998 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700999 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001000 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1001 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001002 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001003 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001004 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001005 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001006
1007 //
1008 // Remove all Flow Entries
1009 //
1010 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1011 for (IFlowEntry flowEntryObj : flowEntries) {
1012 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001013 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001014 }
1015 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001016 op.removeFlowPath(flowObj);
1017 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001018
1019 return true;
1020 }
1021
1022 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001023 * Get a previously added flow.
1024 *
1025 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001026 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001027 */
1028 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001029 public FlowPath getFlow(FlowId flowId) {
1030 IFlowPath flowObj = null;
1031 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001032 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001033 != null) {
1034 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1035 flowId.toString());
1036 } else {
1037 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1038 flowId.toString());
1039 }
1040 } catch (Exception e) {
1041 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001042 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001043 log.error(":getFlow FlowId:{} failed", flowId.toString());
1044 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001045 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001046 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001047 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001048 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001049
1050 //
1051 // Extract the Flow state
1052 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001053 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001054 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001055
1056 return flowPath;
1057 }
1058
1059 /**
1060 * Get all previously added flows by a specific installer for a given
1061 * data path endpoints.
1062 *
1063 * @param installerId the Caller ID of the installer of the flow to get.
1064 * @param dataPathEndpoints the data path endpoints of the flow to get.
1065 * @return the Flow Paths if found, otherwise null.
1066 */
1067 @Override
1068 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1069 DataPathEndpoints dataPathEndpoints) {
1070 //
1071 // TODO: The implementation below is not optimal:
1072 // We fetch all flows, and then return only the subset that match
1073 // the query conditions.
1074 // We should use the appropriate Titan/Gremlin query to filter-out
1075 // the flows as appropriate.
1076 //
1077 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001078 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001079
1080 if (allFlows == null) {
1081 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001082 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001083 }
1084
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001085 for (FlowPath flow : allFlows) {
1086 //
1087 // TODO: String-based comparison is sub-optimal.
1088 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001089 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001090 //
1091 if (! flow.installerId().toString().equals(installerId.toString()))
1092 continue;
1093 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1094 continue;
1095 }
1096 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1097 continue;
1098 }
1099 flowPaths.add(flow);
1100 }
1101
1102 if (flowPaths.isEmpty()) {
1103 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001104 } else {
1105 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1106 }
1107
1108 return flowPaths;
1109 }
1110
1111 /**
1112 * Get all installed flows by all installers for given data path endpoints.
1113 *
1114 * @param dataPathEndpoints the data path endpoints of the flows to get.
1115 * @return the Flow Paths if found, otherwise null.
1116 */
1117 @Override
1118 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1119 //
1120 // TODO: The implementation below is not optimal:
1121 // We fetch all flows, and then return only the subset that match
1122 // the query conditions.
1123 // We should use the appropriate Titan/Gremlin query to filter-out
1124 // the flows as appropriate.
1125 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001126 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1127 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001128
1129 if (allFlows == null) {
1130 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001131 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001132 }
1133
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001134 for (FlowPath flow : allFlows) {
1135 //
1136 // TODO: String-based comparison is sub-optimal.
1137 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001138 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001139 //
1140 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1141 continue;
1142 }
1143 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1144 continue;
1145 }
1146 flowPaths.add(flow);
1147 }
1148
1149 if (flowPaths.isEmpty()) {
1150 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001151 } else {
1152 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1153 }
1154
1155 return flowPaths;
1156 }
1157
1158 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001159 * Get summary of all installed flows by all installers in a given range
1160 *
1161 * @param flowId the data path endpoints of the flows to get.
1162 * @param maxFlows: the maximum number of flows to be returned
1163 * @return the Flow Paths if found, otherwise null.
1164 */
1165 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001166 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001167
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001168 // TODO: The implementation below is not optimal:
1169 // We fetch all flows, and then return only the subset that match
1170 // the query conditions.
1171 // We should use the appropriate Titan/Gremlin query to filter-out
1172 // the flows as appropriate.
1173 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001174 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001175
Jonathan Hart01f2d272013-04-04 20:03:46 -07001176 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1177
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001178 Collections.sort(flowPathsWithoutFlowEntries,
1179 new Comparator<IFlowPath>(){
1180 @Override
1181 public int compare(IFlowPath first, IFlowPath second) {
1182 // TODO Auto-generated method stub
1183 long result = new FlowId(first.getFlowId()).value()
1184 - new FlowId(second.getFlowId()).value();
1185 if (result > 0) return 1;
1186 else if (result < 0) return -1;
1187 else return 0;
1188 }
1189 }
1190 );
1191
Jonathan Hart01f2d272013-04-04 20:03:46 -07001192 return flowPathsWithoutFlowEntries;
1193
1194 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001195 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001196
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001197 if (allFlows == null) {
1198 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001199 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001200 }
1201
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001202 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001203
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001204 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001205 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001206
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001207 // start from desired flowId
1208 if (flow.flowId().value() < flowId.value()) {
1209 continue;
1210 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001211
1212 // Summarize by making null flow entry fields that are not relevant to report
1213 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1214 flowEntry.setFlowEntryActions(null);
1215 flowEntry.setFlowEntryMatch(null);
1216 }
1217
1218 flowPaths.add(flow);
1219 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1220 break;
1221 }
1222 }
1223
1224 if (flowPaths.isEmpty()) {
1225 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001226 } else {
1227 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1228 }
1229
1230 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001231 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001232 }
1233
1234 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001235 * Get all installed flows by all installers.
1236 *
1237 * @return the Flow Paths if found, otherwise null.
1238 */
1239 @Override
1240 public ArrayList<FlowPath> getAllFlows() {
1241 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001242 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001243
1244 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001245 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001246 log.debug("Get all FlowPaths: found FlowPaths");
1247 } else {
1248 log.debug("Get all FlowPaths: no FlowPaths found");
1249 }
1250 } catch (Exception e) {
1251 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001252 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001253 log.error(":getAllFlowPaths failed");
1254 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001255 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001256 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001257 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001258 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001259
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001260 for (IFlowPath flowObj : flowPathsObj) {
1261 //
1262 // Extract the Flow state
1263 //
1264 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001265 if (flowPath != null)
1266 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001267 }
1268
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001269 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001270
1271 return flowPaths;
1272 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001273
1274 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1275 Iterable<IFlowPath> flowPathsObj = null;
1276 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1277 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1278
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001279 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001280
Jonathan Hart01f2d272013-04-04 20:03:46 -07001281 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001282 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001283 log.debug("Get all FlowPaths: found FlowPaths");
1284 } else {
1285 log.debug("Get all FlowPaths: no FlowPaths found");
1286 }
1287 } catch (Exception e) {
1288 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001289 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001290 log.error(":getAllFlowPaths failed");
1291 }
1292 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1293 return new ArrayList<IFlowPath>(); // No Flows found
1294 }
1295
1296 for (IFlowPath flowObj : flowPathsObj){
1297 flowPathsObjArray.add(flowObj);
1298 }
1299 /*
1300 for (IFlowPath flowObj : flowPathsObj) {
1301 //
1302 // Extract the Flow state
1303 //
1304 FlowPath flowPath = extractFlowPath(flowObj);
1305 if (flowPath != null)
1306 flowPaths.add(flowPath);
1307 }
1308 */
1309
1310 //conn.endTx(Transaction.COMMIT);
1311
1312 return flowPathsObjArray;
1313 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001314
1315 /**
1316 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1317 *
1318 * @param flowObj the object to extract the Flow Path State from.
1319 * @return the extracted Flow Path State.
1320 */
1321 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001322 //
1323 // Extract the Flow state
1324 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001325 String flowIdStr = flowObj.getFlowId();
1326 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001327 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001328 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001329 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001330 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001331 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001332
1333 if ((flowIdStr == null) ||
1334 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001335 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001336 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001337 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001338 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001339 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001340 // TODO: A work-around, becauuse of some bogus database objects
1341 return null;
1342 }
1343
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001344 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001345 flowPath.setFlowId(new FlowId(flowIdStr));
1346 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001347 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001348 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001349 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001350 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001351 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001352 //
1353 // Extract the match conditions common for all Flow Entries
1354 //
1355 {
1356 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001357 String matchSrcMac = flowObj.getMatchSrcMac();
1358 if (matchSrcMac != null)
1359 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1360 String matchDstMac = flowObj.getMatchDstMac();
1361 if (matchDstMac != null)
1362 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001363 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1364 if (matchEthernetFrameType != null)
1365 match.enableEthernetFrameType(matchEthernetFrameType);
1366 Short matchVlanId = flowObj.getMatchVlanId();
1367 if (matchVlanId != null)
1368 match.enableVlanId(matchVlanId);
1369 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1370 if (matchVlanPriority != null)
1371 match.enableVlanPriority(matchVlanPriority);
1372 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1373 if (matchSrcIPv4Net != null)
1374 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1375 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1376 if (matchDstIPv4Net != null)
1377 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1378 Byte matchIpProto = flowObj.getMatchIpProto();
1379 if (matchIpProto != null)
1380 match.enableIpProto(matchIpProto);
1381 Byte matchIpToS = flowObj.getMatchIpToS();
1382 if (matchIpToS != null)
1383 match.enableIpToS(matchIpToS);
1384 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1385 if (matchSrcTcpUdpPort != null)
1386 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1387 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1388 if (matchDstTcpUdpPort != null)
1389 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1390
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001391 flowPath.setFlowEntryMatch(match);
1392 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001393 //
1394 // Extract the actions for the first Flow Entry
1395 //
1396 {
1397 String actionsStr = flowObj.getActions();
1398 if (actionsStr != null) {
1399 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1400 flowPath.setFlowEntryActions(flowEntryActions);
1401 }
1402 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001403
1404 //
1405 // Extract all Flow Entries
1406 //
1407 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1408 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001409 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1410 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001411 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001412 flowPath.dataPath().flowEntries().add(flowEntry);
1413 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001414
1415 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001416 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001417
1418 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001419 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1420 *
1421 * @param flowEntryObj the object to extract the Flow Entry State from.
1422 * @return the extracted Flow Entry State.
1423 */
1424 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1425 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1426 String switchDpidStr = flowEntryObj.getSwitchDpid();
1427 String userState = flowEntryObj.getUserState();
1428 String switchState = flowEntryObj.getSwitchState();
1429
1430 if ((flowEntryIdStr == null) ||
1431 (switchDpidStr == null) ||
1432 (userState == null) ||
1433 (switchState == null)) {
1434 // TODO: A work-around, becauuse of some bogus database objects
1435 return null;
1436 }
1437
1438 FlowEntry flowEntry = new FlowEntry();
1439 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1440 flowEntry.setDpid(new Dpid(switchDpidStr));
1441
1442 //
1443 // Extract the match conditions
1444 //
1445 FlowEntryMatch match = new FlowEntryMatch();
1446 Short matchInPort = flowEntryObj.getMatchInPort();
1447 if (matchInPort != null)
1448 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001449 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1450 if (matchSrcMac != null)
1451 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1452 String matchDstMac = flowEntryObj.getMatchDstMac();
1453 if (matchDstMac != null)
1454 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001455 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1456 if (matchEthernetFrameType != null)
1457 match.enableEthernetFrameType(matchEthernetFrameType);
1458 Short matchVlanId = flowEntryObj.getMatchVlanId();
1459 if (matchVlanId != null)
1460 match.enableVlanId(matchVlanId);
1461 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1462 if (matchVlanPriority != null)
1463 match.enableVlanPriority(matchVlanPriority);
1464 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1465 if (matchSrcIPv4Net != null)
1466 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1467 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1468 if (matchDstIPv4Net != null)
1469 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1470 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1471 if (matchIpProto != null)
1472 match.enableIpProto(matchIpProto);
1473 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1474 if (matchIpToS != null)
1475 match.enableIpToS(matchIpToS);
1476 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1477 if (matchSrcTcpUdpPort != null)
1478 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1479 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1480 if (matchDstTcpUdpPort != null)
1481 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001482 flowEntry.setFlowEntryMatch(match);
1483
1484 //
1485 // Extract the actions
1486 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001487 FlowEntryActions actions = new FlowEntryActions();
1488 String actionsStr = flowEntryObj.getActions();
1489 if (actionsStr != null)
1490 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001491 flowEntry.setFlowEntryActions(actions);
1492 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1493 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1494 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001495 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001496 //
1497 return flowEntry;
1498 }
1499
1500 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001501 * Add and maintain a shortest-path flow.
1502 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001503 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001504 *
1505 * @param flowPath the Flow Path with the endpoints and the match
1506 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001507 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001508 */
1509 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001510 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001511 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001512 // Don't do the shortest path computation here.
1513 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001514 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001515
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001516 // We need the DataPath to populate the Network MAP
1517 DataPath dataPath = new DataPath();
1518 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1519 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001520
1521 //
1522 // Prepare the computed Flow Path
1523 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001524 FlowPath computedFlowPath = new FlowPath();
1525 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1526 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001527 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001528 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001529 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001530 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001531
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001532 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001533 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001534 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001535 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001536
1537 // TODO: Mark the flow for maintenance purpose
1538
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001539 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001540 }
1541
1542 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001543 * Reconcile a flow.
1544 *
1545 * @param flowObj the flow that needs to be reconciliated.
1546 * @param newDataPath the new data path to use.
1547 * @return true on success, otherwise false.
1548 */
1549 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1550 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1551
1552 //
1553 // Set the incoming port matching and the outgoing port output
1554 // actions for each flow entry.
1555 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001556 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001557 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1558 // Set the incoming port matching
1559 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1560 flowEntry.setFlowEntryMatch(flowEntryMatch);
1561 flowEntryMatch.enableInPort(flowEntry.inPort());
1562
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001563 //
1564 // Set the actions
1565 //
1566 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1567 //
1568 // If the first Flow Entry, copy the Flow Path actions to it
1569 //
1570 if (idx == 0) {
1571 String actionsStr = flowObj.getActions();
1572 if (actionsStr != null) {
1573 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1574 for (FlowEntryAction action : flowActions.actions())
1575 flowEntryActions.addAction(action);
1576 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001577 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001578 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001579 //
1580 // Add the outgoing port output action
1581 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001582 FlowEntryAction flowEntryAction = new FlowEntryAction();
1583 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001584 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001585 }
1586
1587 //
1588 // Remove the old Flow Entries, and add the new Flow Entries
1589 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001590 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1591 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1592 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001593 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001594 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001595 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001596 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001597 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001598 }
1599
1600 //
1601 // Set the Data Path Summary
1602 //
1603 String dataPathSummaryStr = newDataPath.dataPathSummary();
1604 flowObj.setDataPathSummary(dataPathSummaryStr);
1605
1606 return true;
1607 }
1608
1609 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001610 * Reconcile all flows in a set.
1611 *
1612 * @param flowObjSet the set of flows that need to be reconciliated.
1613 */
1614 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1615 if (! flowObjSet.iterator().hasNext())
1616 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001617 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001618 }
1619
1620 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001621 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001622 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001623 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001624 * @param flowObj the flow path object for the flow entry to install.
1625 * @param flowEntryObj the flow entry object to install.
1626 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001627 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001628 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1629 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001630 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1631 if (flowEntryIdStr == null)
1632 return false;
1633 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001634 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001635 if (userState == null)
1636 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001637
1638 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001639 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001640 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001641 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1642 .getMessage(OFType.FLOW_MOD);
1643 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001644
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001645 short flowModCommand = OFFlowMod.OFPFC_ADD;
1646 if (userState.equals("FE_USER_ADD")) {
1647 flowModCommand = OFFlowMod.OFPFC_ADD;
1648 } else if (userState.equals("FE_USER_MODIFY")) {
1649 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1650 } else if (userState.equals("FE_USER_DELETE")) {
1651 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1652 } else {
1653 // Unknown user state. Ignore the entry
1654 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1655 flowEntryId.toString(), userState);
1656 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001657 }
1658
1659 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001660 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001661 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001662 // NOTE: The Flow matching conditions common for all Flow Entries are
1663 // used ONLY if a Flow Entry does NOT have the corresponding matching
1664 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001665 //
1666 OFMatch match = new OFMatch();
1667 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001668
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001669 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001670 Short matchInPort = flowEntryObj.getMatchInPort();
1671 if (matchInPort != null) {
1672 match.setInputPort(matchInPort);
1673 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1674 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001675
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001676 // Match the Source MAC address
1677 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1678 if (matchSrcMac == null)
1679 matchSrcMac = flowObj.getMatchSrcMac();
1680 if (matchSrcMac != null) {
1681 match.setDataLayerSource(matchSrcMac);
1682 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1683 }
1684
1685 // Match the Destination MAC address
1686 String matchDstMac = flowEntryObj.getMatchDstMac();
1687 if (matchDstMac == null)
1688 matchDstMac = flowObj.getMatchDstMac();
1689 if (matchDstMac != null) {
1690 match.setDataLayerDestination(matchDstMac);
1691 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1692 }
1693
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001694 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001695 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1696 if (matchEthernetFrameType == null)
1697 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1698 if (matchEthernetFrameType != null) {
1699 match.setDataLayerType(matchEthernetFrameType);
1700 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1701 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001702
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001703 // Match the VLAN ID
1704 Short matchVlanId = flowEntryObj.getMatchVlanId();
1705 if (matchVlanId == null)
1706 matchVlanId = flowObj.getMatchVlanId();
1707 if (matchVlanId != null) {
1708 match.setDataLayerVirtualLan(matchVlanId);
1709 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1710 }
1711
1712 // Match the VLAN priority
1713 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1714 if (matchVlanPriority == null)
1715 matchVlanPriority = flowObj.getMatchVlanPriority();
1716 if (matchVlanPriority != null) {
1717 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1718 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1719 }
1720
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001721 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001722 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1723 if (matchSrcIPv4Net == null)
1724 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1725 if (matchSrcIPv4Net != null) {
1726 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1727 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001728
1729 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001730 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1731 if (matchDstIPv4Net == null)
1732 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1733 if (matchDstIPv4Net != null) {
1734 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1735 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001736
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001737 // Match the IP protocol
1738 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1739 if (matchIpProto == null)
1740 matchIpProto = flowObj.getMatchIpProto();
1741 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001742 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001743 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001744 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001745
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001746 // Match the IP ToS (DSCP field, 6 bits)
1747 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1748 if (matchIpToS == null)
1749 matchIpToS = flowObj.getMatchIpToS();
1750 if (matchIpToS != null) {
1751 match.setNetworkTypeOfService(matchIpToS);
1752 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1753 }
1754
1755 // Match the Source TCP/UDP port
1756 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1757 if (matchSrcTcpUdpPort == null)
1758 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1759 if (matchSrcTcpUdpPort != null) {
1760 match.setTransportSource(matchSrcTcpUdpPort);
1761 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1762 }
1763
1764 // Match the Destination TCP/UDP port
1765 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1766 if (matchDstTcpUdpPort == null)
1767 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1768 if (matchDstTcpUdpPort != null) {
1769 match.setTransportDestination(matchDstTcpUdpPort);
1770 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001771 }
1772
1773 //
1774 // Fetch the actions
1775 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001776 Short actionOutputPort = null;
1777 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1778 int actionsLen = 0;
1779 FlowEntryActions flowEntryActions = null;
1780 String actionsStr = flowEntryObj.getActions();
1781 if (actionsStr != null)
1782 flowEntryActions = new FlowEntryActions(actionsStr);
1783 for (FlowEntryAction action : flowEntryActions.actions()) {
1784 ActionOutput actionOutput = action.actionOutput();
1785 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1786 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1787 ActionStripVlan actionStripVlan = action.actionStripVlan();
1788 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1789 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1790 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1791 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1792 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1793 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1794 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1795 ActionEnqueue actionEnqueue = action.actionEnqueue();
1796
1797 if (actionOutput != null) {
1798 actionOutputPort = actionOutput.port().value();
1799 // XXX: The max length is hard-coded for now
1800 OFActionOutput ofa =
1801 new OFActionOutput(actionOutput.port().value(),
1802 (short)0xffff);
1803 openFlowActions.add(ofa);
1804 actionsLen += ofa.getLength();
1805 }
1806
1807 if (actionSetVlanId != null) {
1808 OFActionVirtualLanIdentifier ofa =
1809 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1810 openFlowActions.add(ofa);
1811 actionsLen += ofa.getLength();
1812 }
1813
1814 if (actionSetVlanPriority != null) {
1815 OFActionVirtualLanPriorityCodePoint ofa =
1816 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1817 openFlowActions.add(ofa);
1818 actionsLen += ofa.getLength();
1819 }
1820
1821 if (actionStripVlan != null) {
1822 if (actionStripVlan.stripVlan() == true) {
1823 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1824 openFlowActions.add(ofa);
1825 actionsLen += ofa.getLength();
1826 }
1827 }
1828
1829 if (actionSetEthernetSrcAddr != null) {
1830 OFActionDataLayerSource ofa =
1831 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1832 openFlowActions.add(ofa);
1833 actionsLen += ofa.getLength();
1834 }
1835
1836 if (actionSetEthernetDstAddr != null) {
1837 OFActionDataLayerDestination ofa =
1838 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1839 openFlowActions.add(ofa);
1840 actionsLen += ofa.getLength();
1841 }
1842
1843 if (actionSetIPv4SrcAddr != null) {
1844 OFActionNetworkLayerSource ofa =
1845 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1846 openFlowActions.add(ofa);
1847 actionsLen += ofa.getLength();
1848 }
1849
1850 if (actionSetIPv4DstAddr != null) {
1851 OFActionNetworkLayerDestination ofa =
1852 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1853 openFlowActions.add(ofa);
1854 actionsLen += ofa.getLength();
1855 }
1856
1857 if (actionSetIpToS != null) {
1858 OFActionNetworkTypeOfService ofa =
1859 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1860 openFlowActions.add(ofa);
1861 actionsLen += ofa.getLength();
1862 }
1863
1864 if (actionSetTcpUdpSrcPort != null) {
1865 OFActionTransportLayerSource ofa =
1866 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1867 openFlowActions.add(ofa);
1868 actionsLen += ofa.getLength();
1869 }
1870
1871 if (actionSetTcpUdpDstPort != null) {
1872 OFActionTransportLayerDestination ofa =
1873 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1874 openFlowActions.add(ofa);
1875 actionsLen += ofa.getLength();
1876 }
1877
1878 if (actionEnqueue != null) {
1879 OFActionEnqueue ofa =
1880 new OFActionEnqueue(actionEnqueue.port().value(),
1881 actionEnqueue.queueId());
1882 openFlowActions.add(ofa);
1883 actionsLen += ofa.getLength();
1884 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001885 }
1886
1887 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1888 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1889 .setPriority(PRIORITY_DEFAULT)
1890 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1891 .setCookie(cookie)
1892 .setCommand(flowModCommand)
1893 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001894 .setActions(openFlowActions)
1895 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001896 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1897 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1898 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1899 if (actionOutputPort != null)
1900 fm.setOutPort(actionOutputPort);
1901 }
1902
1903 //
1904 // TODO: Set the following flag
1905 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1906 // See method ForwardingBase::pushRoute()
1907 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001908
1909 //
1910 // Write the message to the switch
1911 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001912 log.debug("MEASUREMENT: Installing flow entry " + userState +
1913 " into switch DPID: " +
1914 mySwitch.getStringId() +
1915 " flowEntryId: " + flowEntryId.toString() +
1916 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1917 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1918 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001919 try {
1920 messageDamper.write(mySwitch, fm, null);
1921 mySwitch.flush();
1922 //
1923 // TODO: We should use the OpenFlow Barrier mechanism
1924 // to check for errors, and update the SwitchState
1925 // for a flow entry after the Barrier message is
1926 // is received.
1927 //
1928 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1929 } catch (IOException e) {
1930 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001931 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001932 }
1933
1934 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001935 }
1936
1937 /**
1938 * Install a Flow Entry on a switch.
1939 *
1940 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001941 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001942 * @param flowEntry the flow entry to install.
1943 * @return true on success, otherwise false.
1944 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001945 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1946 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001947 //
1948 // Create the OpenFlow Flow Modification Entry to push
1949 //
1950 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1951 .getMessage(OFType.FLOW_MOD);
1952 long cookie = flowEntry.flowEntryId().value();
1953
1954 short flowModCommand = OFFlowMod.OFPFC_ADD;
1955 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1956 flowModCommand = OFFlowMod.OFPFC_ADD;
1957 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1958 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1959 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1960 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1961 } else {
1962 // Unknown user state. Ignore the entry
1963 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1964 flowEntry.flowEntryId().toString(),
1965 flowEntry.flowEntryUserState());
1966 return false;
1967 }
1968
1969 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001970 // Fetch the match conditions.
1971 //
1972 // NOTE: The Flow matching conditions common for all Flow Entries are
1973 // used ONLY if a Flow Entry does NOT have the corresponding matching
1974 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001975 //
1976 OFMatch match = new OFMatch();
1977 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001978 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1979 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1980
1981 // Match the Incoming Port
1982 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001983 if (matchInPort != null) {
1984 match.setInputPort(matchInPort.value());
1985 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1986 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001987
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001988 // Match the Source MAC address
1989 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1990 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1991 matchSrcMac = flowPathMatch.srcMac();
1992 }
1993 if (matchSrcMac != null) {
1994 match.setDataLayerSource(matchSrcMac.toString());
1995 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1996 }
1997
1998 // Match the Destination MAC address
1999 MACAddress matchDstMac = flowEntryMatch.dstMac();
2000 if ((matchDstMac == null) && (flowPathMatch != null)) {
2001 matchDstMac = flowPathMatch.dstMac();
2002 }
2003 if (matchDstMac != null) {
2004 match.setDataLayerDestination(matchDstMac.toString());
2005 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2006 }
2007
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002008 // Match the Ethernet Frame Type
2009 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2010 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2011 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2012 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002013 if (matchEthernetFrameType != null) {
2014 match.setDataLayerType(matchEthernetFrameType);
2015 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2016 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002017
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002018 // Match the VLAN ID
2019 Short matchVlanId = flowEntryMatch.vlanId();
2020 if ((matchVlanId == null) && (flowPathMatch != null)) {
2021 matchVlanId = flowPathMatch.vlanId();
2022 }
2023 if (matchVlanId != null) {
2024 match.setDataLayerVirtualLan(matchVlanId);
2025 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2026 }
2027
2028 // Match the VLAN priority
2029 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2030 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2031 matchVlanPriority = flowPathMatch.vlanPriority();
2032 }
2033 if (matchVlanPriority != null) {
2034 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2035 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2036 }
2037
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002038 // Match the Source IPv4 Network prefix
2039 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2040 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2041 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2042 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002043 if (matchSrcIPv4Net != null) {
2044 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2045 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002046
2047 // Natch the Destination IPv4 Network prefix
2048 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2049 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2050 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2051 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002052 if (matchDstIPv4Net != null) {
2053 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2054 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002055
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002056 // Match the IP protocol
2057 Byte matchIpProto = flowEntryMatch.ipProto();
2058 if ((matchIpProto == null) && (flowPathMatch != null)) {
2059 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002060 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002061 if (matchIpProto != null) {
2062 match.setNetworkProtocol(matchIpProto);
2063 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002064 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002065
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002066 // Match the IP ToS (DSCP field, 6 bits)
2067 Byte matchIpToS = flowEntryMatch.ipToS();
2068 if ((matchIpToS == null) && (flowPathMatch != null)) {
2069 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002070 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002071 if (matchIpToS != null) {
2072 match.setNetworkTypeOfService(matchIpToS);
2073 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2074 }
2075
2076 // Match the Source TCP/UDP port
2077 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2078 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2079 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2080 }
2081 if (matchSrcTcpUdpPort != null) {
2082 match.setTransportSource(matchSrcTcpUdpPort);
2083 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2084 }
2085
2086 // Match the Destination TCP/UDP port
2087 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2088 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2089 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2090 }
2091 if (matchDstTcpUdpPort != null) {
2092 match.setTransportDestination(matchDstTcpUdpPort);
2093 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002094 }
2095
2096 //
2097 // Fetch the actions
2098 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002099 Short actionOutputPort = null;
2100 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2101 int actionsLen = 0;
2102 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002103 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002104 for (FlowEntryAction action : flowEntryActions.actions()) {
2105 ActionOutput actionOutput = action.actionOutput();
2106 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2107 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2108 ActionStripVlan actionStripVlan = action.actionStripVlan();
2109 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2110 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2111 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2112 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2113 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2114 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2115 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2116 ActionEnqueue actionEnqueue = action.actionEnqueue();
2117
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002118 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002119 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002120 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002121 OFActionOutput ofa =
2122 new OFActionOutput(actionOutput.port().value(),
2123 (short)0xffff);
2124 openFlowActions.add(ofa);
2125 actionsLen += ofa.getLength();
2126 }
2127
2128 if (actionSetVlanId != null) {
2129 OFActionVirtualLanIdentifier ofa =
2130 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2131 openFlowActions.add(ofa);
2132 actionsLen += ofa.getLength();
2133 }
2134
2135 if (actionSetVlanPriority != null) {
2136 OFActionVirtualLanPriorityCodePoint ofa =
2137 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2138 openFlowActions.add(ofa);
2139 actionsLen += ofa.getLength();
2140 }
2141
2142 if (actionStripVlan != null) {
2143 if (actionStripVlan.stripVlan() == true) {
2144 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2145 openFlowActions.add(ofa);
2146 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002147 }
2148 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002149
2150 if (actionSetEthernetSrcAddr != null) {
2151 OFActionDataLayerSource ofa =
2152 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2153 openFlowActions.add(ofa);
2154 actionsLen += ofa.getLength();
2155 }
2156
2157 if (actionSetEthernetDstAddr != null) {
2158 OFActionDataLayerDestination ofa =
2159 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2160 openFlowActions.add(ofa);
2161 actionsLen += ofa.getLength();
2162 }
2163
2164 if (actionSetIPv4SrcAddr != null) {
2165 OFActionNetworkLayerSource ofa =
2166 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2167 openFlowActions.add(ofa);
2168 actionsLen += ofa.getLength();
2169 }
2170
2171 if (actionSetIPv4DstAddr != null) {
2172 OFActionNetworkLayerDestination ofa =
2173 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2174 openFlowActions.add(ofa);
2175 actionsLen += ofa.getLength();
2176 }
2177
2178 if (actionSetIpToS != null) {
2179 OFActionNetworkTypeOfService ofa =
2180 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2181 openFlowActions.add(ofa);
2182 actionsLen += ofa.getLength();
2183 }
2184
2185 if (actionSetTcpUdpSrcPort != null) {
2186 OFActionTransportLayerSource ofa =
2187 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2188 openFlowActions.add(ofa);
2189 actionsLen += ofa.getLength();
2190 }
2191
2192 if (actionSetTcpUdpDstPort != null) {
2193 OFActionTransportLayerDestination ofa =
2194 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2195 openFlowActions.add(ofa);
2196 actionsLen += ofa.getLength();
2197 }
2198
2199 if (actionEnqueue != null) {
2200 OFActionEnqueue ofa =
2201 new OFActionEnqueue(actionEnqueue.port().value(),
2202 actionEnqueue.queueId());
2203 openFlowActions.add(ofa);
2204 actionsLen += ofa.getLength();
2205 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002206 }
2207
2208 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2209 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2210 .setPriority(PRIORITY_DEFAULT)
2211 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2212 .setCookie(cookie)
2213 .setCommand(flowModCommand)
2214 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002215 .setActions(openFlowActions)
2216 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2217 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2218 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2219 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2220 if (actionOutputPort != null)
2221 fm.setOutPort(actionOutputPort);
2222 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002223
2224 //
2225 // TODO: Set the following flag
2226 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2227 // See method ForwardingBase::pushRoute()
2228 //
2229
2230 //
2231 // Write the message to the switch
2232 //
2233 try {
2234 messageDamper.write(mySwitch, fm, null);
2235 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002236 //
2237 // TODO: We should use the OpenFlow Barrier mechanism
2238 // to check for errors, and update the SwitchState
2239 // for a flow entry after the Barrier message is
2240 // is received.
2241 //
2242 // TODO: The FlowEntry Object in Titan should be set
2243 // to FE_SWITCH_UPDATED.
2244 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002245 } catch (IOException e) {
2246 log.error("Failure writing flow mod from network map", e);
2247 return false;
2248 }
2249 return true;
2250 }
2251
2252 /**
2253 * Remove a Flow Entry from a switch.
2254 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002255 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002256 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002257 * @param flowEntry the flow entry to remove.
2258 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002259 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002260 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2261 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002262 //
2263 // The installFlowEntry() method implements both installation
2264 // and removal of flow entries.
2265 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002266 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002267 }
2268
2269 /**
2270 * Install a Flow Entry on a remote controller.
2271 *
2272 * TODO: We need it now: Jono
2273 * - For now it will make a REST call to the remote controller.
2274 * - Internally, it needs to know the name of the remote controller.
2275 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002276 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002277 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002278 * @return true on success, otherwise false.
2279 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002280 public boolean installRemoteFlowEntry(FlowPath flowPath,
2281 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002282 // TODO: We need it now: Jono
2283 // - For now it will make a REST call to the remote controller.
2284 // - Internally, it needs to know the name of the remote controller.
2285 return true;
2286 }
2287
2288 /**
2289 * Remove a flow entry on a remote controller.
2290 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002291 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002292 * @param flowEntry the flow entry to remove.
2293 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002294 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002295 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2296 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002297 //
2298 // The installRemoteFlowEntry() method implements both installation
2299 // and removal of flow entries.
2300 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002301 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002302 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002303}