blob: 2b3b0f219ee54321552f21e05d734b597571a4bd [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();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700130 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700131 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700132 return;
133 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700134 LinkedList<IFlowEntry> addFlowEntries =
135 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000136 LinkedList<IFlowEntry> deleteFlowEntries =
137 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700138
139 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700140 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700141 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700142 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700143 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000144 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700145 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700146 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700147 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000148
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000149 String dpidStr = flowEntryObj.getSwitchDpid();
150 if (dpidStr == null)
151 continue;
152 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800153 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000154 if (mySwitch == null)
155 continue; // Ignore the entry: not my switch
156
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700157 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700158 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700159 if (flowObj == null)
160 continue; // Should NOT happen
161 if (flowObj.getFlowId() == null)
162 continue; // Invalid entry
163
164 //
165 // NOTE: For now we process the DELETE before the ADD
166 // to cover the more common scenario.
167 // TODO: This is error prone and needs to be fixed!
168 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000169 String userState = flowEntryObj.getUserState();
170 if (userState == null)
171 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700172 if (userState.equals("FE_USER_DELETE")) {
173 // An entry that needs to be deleted.
174 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700175 installFlowEntry(mySwitch, flowObj, flowEntryObj);
176 } else {
177 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700178 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700179 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700180 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700181 // TODO: Commented-out for now
182 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700183 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700184 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700185 processed_measurement_flow = true;
186 }
187 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700188 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700189 }
190
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700191 //
192 // Process the Flow Entries that need to be added
193 //
194 for (IFlowEntry flowEntryObj : addFlowEntries) {
195 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700196 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700197 if (flowObj == null)
198 continue; // Should NOT happen
199 if (flowObj.getFlowId() == null)
200 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700201
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700203 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000204 if (mySwitch == null)
205 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700206 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800207 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000208
209 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000210 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700211 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000212 //
213 // TODO: We should use the OpenFlow Barrier mechanism
214 // to check for errors, and delete the Flow Entries after the
215 // Barrier message is received.
216 //
217 while (! deleteFlowEntries.isEmpty()) {
218 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
219 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700220 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000221 if (flowObj == null) {
222 log.debug("Did not find FlowPath to be deleted");
223 continue;
224 }
225 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700226 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000227 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700228
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700229 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700230
231 if (processed_measurement_flow) {
232 long estimatedTime =
233 System.nanoTime() - modifiedMeasurementFlowTime;
234 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
235 (double)estimatedTime / 1000000000 + " sec";
236 log.debug(logMsg);
237 }
238
239 long estimatedTime = System.nanoTime() - startTime;
240 double rate = 0.0;
241 if (estimatedTime > 0)
242 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
243 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
244 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
245 counterMyNotUpdatedFlowEntries + " in " +
246 (double)estimatedTime / 1000000000 + " sec: " +
247 rate + " paths/s";
248 log.debug(logMsg);
249 }
250 };
251
252 final Runnable shortestPathReconcile = new Runnable() {
253 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700254 try {
255 runImpl();
256 } catch (Exception e) {
257 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700258 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700259 return;
260 }
261 }
262
263 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700264 long startTime = System.nanoTime();
265 int counterAllFlowPaths = 0;
266 int counterMyFlowPaths = 0;
267
268 if (floodlightProvider == null) {
269 log.debug("FloodlightProvider service not found!");
270 return;
271 }
272 Map<Long, IOFSwitch> mySwitches =
273 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700274 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700275 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700276 return;
277 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700278 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
279
280 boolean processed_measurement_flow = false;
281
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700282 //
283 // Fetch and recompute the Shortest Path for those
284 // Flow Paths this controller is responsible for.
285 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000286 Map<Long, ?> shortestPathTopo =
287 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700288 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700289 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700290 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291 if (flowPathObj == null)
292 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700293
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700294 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000295 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700296 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700297 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700298 //
299 // Use the source DPID as a heuristic to decide
300 // which controller is responsible for maintaining the
301 // shortest path.
302 // NOTE: This heuristic is error-prone: if the switch
303 // goes away and no controller is responsible for that
304 // switch, then the original Flow Path is not cleaned-up
305 //
306 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
307 if (mySwitch == null)
308 continue; // Ignore: not my responsibility
309
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700310 // Test the Data Path Summary string
311 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
312 if (dataPathSummaryStr == null)
313 continue; // Could be invalid entry?
314 if (dataPathSummaryStr.isEmpty())
315 continue; // No need to maintain this flow
316
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000317 //
318 // Test whether we need to complete the Flow cleanup,
319 // if the Flow has been deleted by the user.
320 //
321 String flowUserState = flowPathObj.getUserState();
322 if ((flowUserState != null)
323 && flowUserState.equals("FE_USER_DELETE")) {
324 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
325 boolean empty = true; // TODO: an ugly hack
326 for (IFlowEntry flowEntryObj : flowEntries) {
327 empty = false;
328 break;
329 }
330 if (empty)
331 deleteFlows.add(flowPathObj);
332 }
333
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000334 // Fetch the fields needed to recompute the shortest path
335 Short srcPortShort = flowPathObj.getSrcPort();
336 String dstDpidStr = flowPathObj.getDstSwitch();
337 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700338 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000339 if ((srcPortShort == null) ||
340 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700341 (dstPortShort == null) ||
342 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000343 continue;
344 }
345
346 Port srcPort = new Port(srcPortShort);
347 Dpid dstDpid = new Dpid(dstDpidStr);
348 Port dstPort = new Port(dstPortShort);
349 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
350 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700351 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000352
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700353 counterMyFlowPaths++;
354
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700355 //
356 // NOTE: Using here the regular getShortestPath() method
357 // won't work here, because that method calls internally
358 // "conn.endTx(Transaction.COMMIT)", and that will
359 // invalidate all handlers to the Titan database.
360 // If we want to experiment with calling here
361 // getShortestPath(), we need to refactor that code
362 // to avoid closing the transaction.
363 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700364 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000365 topoRouteService.getTopoShortestPath(shortestPathTopo,
366 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700367 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000368 if (dataPath == null) {
369 // We need the DataPath to compare the paths
370 dataPath = new DataPath();
371 dataPath.setSrcPort(srcSwitchPort);
372 dataPath.setDstPort(dstSwitchPort);
373 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700374 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000375
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700376 String newDataPathSummaryStr = dataPath.dataPathSummary();
377 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
378 continue; // Nothing changed
379
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700380 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700381 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000382
383 //
384 // Delete all leftover Flows marked for deletion from the
385 // Network MAP.
386 //
387 while (! deleteFlows.isEmpty()) {
388 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700389 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000390 }
391
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000392 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700393
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700394 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700395
396 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700397 long estimatedTime =
398 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700399 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
400 (double)estimatedTime / 1000000000 + " sec";
401 log.debug(logMsg);
402 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700403
404 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700405 double rate = 0.0;
406 if (estimatedTime > 0)
407 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700408 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700409 counterAllFlowPaths + " MyFlowPaths: " +
410 counterMyFlowPaths + " in " +
411 (double)estimatedTime / 1000000000 + " sec: " +
412 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700413 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800414 }
415 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700416
Jonathan Hart50a94982013-04-10 14:49:51 -0700417 //final ScheduledFuture<?> mapReaderHandle =
418 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800419
Jonathan Hart50a94982013-04-10 14:49:51 -0700420 //final ScheduledFuture<?> shortestPathReconcileHandle =
421 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700422
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800423 @Override
424 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700425 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700426 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800427 }
428
429 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700430 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800431 }
432
433 @Override
434 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700435 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800436 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800437
438 @Override
439 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
440 Collection<Class<? extends IFloodlightService>> l =
441 new ArrayList<Class<? extends IFloodlightService>>();
442 l.add(IFlowService.class);
443 return l;
444 }
445
446 @Override
447 public Map<Class<? extends IFloodlightService>, IFloodlightService>
448 getServiceImpls() {
449 Map<Class<? extends IFloodlightService>,
450 IFloodlightService> m =
451 new HashMap<Class<? extends IFloodlightService>,
452 IFloodlightService>();
453 m.put(IFlowService.class, this);
454 return m;
455 }
456
457 @Override
458 public Collection<Class<? extends IFloodlightService>>
459 getModuleDependencies() {
460 Collection<Class<? extends IFloodlightService>> l =
461 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800462 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 l.add(IRestApiService.class);
464 return l;
465 }
466
467 @Override
468 public void init(FloodlightModuleContext context)
469 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700470 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800471 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800472 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800473 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
474 EnumSet.of(OFType.FLOW_MOD),
475 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700476
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800477 // TODO: An ugly hack!
478 String conf = "/tmp/cassandra.titan";
479 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700480
481 mapReaderScheduler = Executors.newScheduledThreadPool(1);
482 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800483 }
484
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700485 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000486 //
487 // Generate the next Flow Entry ID.
488 // NOTE: For now, the higher 32 bits are random, and
489 // the lower 32 bits are sequential.
490 // In the future, we need a better allocation mechanism.
491 //
492 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
493 nextFlowEntryIdPrefix = randomGenerator.nextInt();
494 nextFlowEntryIdSuffix = 0;
495 } else {
496 nextFlowEntryIdSuffix++;
497 }
498 long result = (long)nextFlowEntryIdPrefix << 32;
499 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
500 return result;
501 }
502
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800503 @Override
504 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700505 restApi.addRestletRoutable(new FlowWebRoutable());
506
507 // Initialize the Flow Entry ID generator
508 nextFlowEntryIdPrefix = randomGenerator.nextInt();
509
510 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200511 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700512 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200513 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800514 }
515
516 /**
517 * Add a flow.
518 *
519 * Internally, ONOS will automatically register the installer for
520 * receiving Flow Path Notifications for that path.
521 *
522 * @param flowPath the Flow Path to install.
523 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700524 * @param dataPathSummaryStr the data path summary string if the added
525 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800526 * @return true on success, otherwise false.
527 */
528 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700529 public boolean addFlow(FlowPath flowPath, FlowId flowId,
530 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700531 /*
532 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700533 if (flowPath.flowId().value() == measurementFlowId) {
534 modifiedMeasurementFlowTime = System.nanoTime();
535 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700536 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800537
538 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000539 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800540 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700541 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800542 != null) {
543 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
544 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000545 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800546 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700547 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800548 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
549 flowPath.flowId().toString());
550 }
551 } catch (Exception e) {
552 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700553 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000554
555 StringWriter sw = new StringWriter();
556 e.printStackTrace(new PrintWriter(sw));
557 String stacktrace = sw.toString();
558
559 log.error(":addFlow FlowId:{} failed: {}",
560 flowPath.flowId().toString(),
561 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800562 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700563 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000564 log.error(":addFlow FlowId:{} failed: Flow object not created",
565 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700566 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800567 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700568 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800569
570 //
571 // Set the Flow key:
572 // - flowId
573 //
574 flowObj.setFlowId(flowPath.flowId().toString());
575 flowObj.setType("flow");
576
577 //
578 // Set the Flow attributes:
579 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700580 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800581 // - flowPath.dataPath().srcPort()
582 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700583 // - flowPath.matchSrcMac()
584 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700585 // - flowPath.matchEthernetFrameType()
586 // - flowPath.matchVlanId()
587 // - flowPath.matchVlanPriority()
588 // - flowPath.matchSrcIPv4Net()
589 // - flowPath.matchDstIPv4Net()
590 // - flowPath.matchIpProto()
591 // - flowPath.matchIpToS()
592 // - flowPath.matchSrcTcpUdpPort()
593 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700594 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800595 //
596 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700597 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800598 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
599 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
600 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
601 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700602 if (flowPath.flowEntryMatch().matchSrcMac()) {
603 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
604 }
605 if (flowPath.flowEntryMatch().matchDstMac()) {
606 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
607 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700608 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
609 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
610 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700611 if (flowPath.flowEntryMatch().matchVlanId()) {
612 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
613 }
614 if (flowPath.flowEntryMatch().matchVlanPriority()) {
615 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
616 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700617 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
618 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
619 }
620 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
621 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
622 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700623 if (flowPath.flowEntryMatch().matchIpProto()) {
624 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700625 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700626 if (flowPath.flowEntryMatch().matchIpToS()) {
627 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
628 }
629 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
630 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
631 }
632 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
633 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700634 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700635 if (! flowPath.flowEntryActions().actions().isEmpty()) {
636 flowObj.setActions(flowPath.flowEntryActions().toString());
637 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800638
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700639 if (dataPathSummaryStr != null) {
640 flowObj.setDataPathSummary(dataPathSummaryStr);
641 } else {
642 flowObj.setDataPathSummary("");
643 }
644
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000645 if (found)
646 flowObj.setUserState("FE_USER_MODIFY");
647 else
648 flowObj.setUserState("FE_USER_ADD");
649
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800650 // Flow edges:
651 // HeadFE
652
653
654 //
655 // Flow Entries:
656 // flowPath.dataPath().flowEntries()
657 //
658 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700659 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700660 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800661 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700662 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800663 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700664 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800665
666 //
667 // TODO: We need a proper Flow ID allocation mechanism.
668 //
669 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700670
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800671 return true;
672 }
673
674 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700675 * Add a flow entry to the Network MAP.
676 *
677 * @param flowObj the corresponding Flow Path object for the Flow Entry.
678 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700679 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700680 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700681 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700682 // Flow edges
683 // HeadFE (TODO)
684
685 //
686 // Assign the FlowEntry ID.
687 //
688 if ((flowEntry.flowEntryId() == null) ||
689 (flowEntry.flowEntryId().value() == 0)) {
690 long id = getNextFlowEntryId();
691 flowEntry.setFlowEntryId(new FlowEntryId(id));
692 }
693
694 IFlowEntry flowEntryObj = null;
695 boolean found = false;
696 try {
697 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700698 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700699 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
700 flowEntry.flowEntryId().toString());
701 found = true;
702 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700703 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700704 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
705 flowEntry.flowEntryId().toString());
706 }
707 } catch (Exception e) {
708 log.error(":addFlow FlowEntryId:{} failed",
709 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700710 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700711 }
712 if (flowEntryObj == null) {
713 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
714 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700715 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700716 }
717
718 //
719 // Set the Flow Entry key:
720 // - flowEntry.flowEntryId()
721 //
722 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
723 flowEntryObj.setType("flow_entry");
724
725 //
726 // Set the Flow Entry Edges and attributes:
727 // - Switch edge
728 // - InPort edge
729 // - OutPort edge
730 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700731 // - flowEntry.dpid()
732 // - flowEntry.flowEntryUserState()
733 // - flowEntry.flowEntrySwitchState()
734 // - flowEntry.flowEntryErrorState()
735 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700736 // - flowEntry.matchSrcMac()
737 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700738 // - flowEntry.matchEthernetFrameType()
739 // - flowEntry.matchVlanId()
740 // - flowEntry.matchVlanPriority()
741 // - flowEntry.matchSrcIPv4Net()
742 // - flowEntry.matchDstIPv4Net()
743 // - flowEntry.matchIpProto()
744 // - flowEntry.matchIpToS()
745 // - flowEntry.matchSrcTcpUdpPort()
746 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700747 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700748 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700749 //
750 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700751 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700752 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
753 flowEntryObj.setSwitch(sw);
754 if (flowEntry.flowEntryMatch().matchInPort()) {
755 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700756 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700757 flowEntry.flowEntryMatch().inPort().value());
758 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
759 flowEntryObj.setInPort(inport);
760 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700761 if (flowEntry.flowEntryMatch().matchSrcMac()) {
762 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
763 }
764 if (flowEntry.flowEntryMatch().matchDstMac()) {
765 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
766 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700767 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
768 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
769 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700770 if (flowEntry.flowEntryMatch().matchVlanId()) {
771 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
772 }
773 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
774 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
775 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700776 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
777 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
778 }
779 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
780 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
781 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700782 if (flowEntry.flowEntryMatch().matchIpProto()) {
783 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700784 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700785 if (flowEntry.flowEntryMatch().matchIpToS()) {
786 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
787 }
788 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
789 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
790 }
791 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
792 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700793 }
794
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700795 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700796 if (fa.actionOutput() != null) {
797 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700798 op.searchPort(flowEntry.dpid().toString(),
799 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700800 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700801 flowEntryObj.setOutPort(outport);
802 }
803 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700804 if (! flowEntry.flowEntryActions().isEmpty()) {
805 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
806 }
807
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700808 // TODO: Hacks with hard-coded state names!
809 if (found)
810 flowEntryObj.setUserState("FE_USER_MODIFY");
811 else
812 flowEntryObj.setUserState("FE_USER_ADD");
813 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
814 //
815 // TODO: Take care of the FlowEntryErrorState.
816 //
817
818 // Flow Entries edges:
819 // Flow
820 // NextFE (TODO)
821 if (! found) {
822 flowObj.addFlowEntry(flowEntryObj);
823 flowEntryObj.setFlow(flowObj);
824 }
825
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700826 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700827 }
828
829 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000830 * Delete all previously added flows.
831 *
832 * @return true on success, otherwise false.
833 */
834 @Override
835 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000836 List<Thread> threads = new LinkedList<Thread>();
837 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
838 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000839
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000840 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700841 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000842 for (IFlowPath flowPathObj : allFlowPaths) {
843 if (flowPathObj == null)
844 continue;
845 String flowIdStr = flowPathObj.getFlowId();
846 if (flowIdStr == null)
847 continue;
848 FlowId flowId = new FlowId(flowIdStr);
849 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000850 }
851
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000852 // Delete all flows one-by-one
853 for (FlowId flowId : concurrentAllFlowIds)
854 deleteFlow(flowId);
855
856 /*
857 * TODO: A faster mechanism to delete the Flow Paths by using
858 * a number of threads. Commented-out for now.
859 */
860 /*
861 //
862 // Create the threads to delete the Flow Paths
863 //
864 for (int i = 0; i < 10; i++) {
865 Thread thread = new Thread(new Runnable() {
866 @Override
867 public void run() {
868 while (true) {
869 FlowId flowId = concurrentAllFlowIds.poll();
870 if (flowId == null)
871 return;
872 deleteFlow(flowId);
873 }
874 }}, "Delete All Flow Paths");
875 threads.add(thread);
876 }
877
878 // Start processing
879 for (Thread thread : threads) {
880 thread.start();
881 }
882
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000883 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000884 for (Thread thread : threads) {
885 try {
886 thread.join();
887 } catch (InterruptedException e) {
888 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
889 }
890 }
891 */
892
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000893 return true;
894 }
895
896 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800897 * Delete a previously added flow.
898 *
899 * @param flowId the Flow ID of the flow to delete.
900 * @return true on success, otherwise false.
901 */
902 @Override
903 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700904 /*
905 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700906 if (flowId.value() == measurementFlowId) {
907 modifiedMeasurementFlowTime = System.nanoTime();
908 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700909 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700910
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800911 IFlowPath flowObj = null;
912 //
913 // We just mark the entries for deletion,
914 // and let the switches remove each individual entry after
915 // it has been removed from the switches.
916 //
917 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700918 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800919 != null) {
920 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
921 flowId.toString());
922 } else {
923 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
924 flowId.toString());
925 }
926 } catch (Exception e) {
927 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700928 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800929 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
930 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700931 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700932 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800933 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700934 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800935
936 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000937 // Find and mark for deletion all Flow Entries,
938 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800939 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000940 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800941 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
942 boolean empty = true; // TODO: an ugly hack
943 for (IFlowEntry flowEntryObj : flowEntries) {
944 empty = false;
945 // flowObj.removeFlowEntry(flowEntryObj);
946 // conn.utils().removeFlowEntry(conn, flowEntryObj);
947 flowEntryObj.setUserState("FE_USER_DELETE");
948 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
949 }
950 // Remove from the database empty flows
951 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700952 op.removeFlowPath(flowObj);
953 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800954
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800955 return true;
956 }
957
958 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000959 * Clear the state for all previously added flows.
960 *
961 * @return true on success, otherwise false.
962 */
963 @Override
964 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000965 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000966
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000967 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700968 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000969 for (IFlowPath flowPathObj : allFlowPaths) {
970 if (flowPathObj == null)
971 continue;
972 String flowIdStr = flowPathObj.getFlowId();
973 if (flowIdStr == null)
974 continue;
975 FlowId flowId = new FlowId(flowIdStr);
976 allFlowIds.add(flowId);
977 }
978
979 // Clear all flows one-by-one
980 for (FlowId flowId : allFlowIds) {
981 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000982 }
983
984 return true;
985 }
986
987 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700988 * Clear the state for a previously added flow.
989 *
990 * @param flowId the Flow ID of the flow to clear.
991 * @return true on success, otherwise false.
992 */
993 @Override
994 public boolean clearFlow(FlowId flowId) {
995 IFlowPath flowObj = null;
996 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700997 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700998 != null) {
999 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1000 flowId.toString());
1001 } else {
1002 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1003 flowId.toString());
1004 }
1005 } catch (Exception e) {
1006 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001007 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001008 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1009 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001010 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001011 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001012 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001013 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001014
1015 //
1016 // Remove all Flow Entries
1017 //
1018 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1019 for (IFlowEntry flowEntryObj : flowEntries) {
1020 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001021 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001022 }
1023 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001024 op.removeFlowPath(flowObj);
1025 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001026
1027 return true;
1028 }
1029
1030 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001031 * Get a previously added flow.
1032 *
1033 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001034 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001035 */
1036 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001037 public FlowPath getFlow(FlowId flowId) {
1038 IFlowPath flowObj = null;
1039 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001040 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001041 != null) {
1042 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1043 flowId.toString());
1044 } else {
1045 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1046 flowId.toString());
1047 }
1048 } catch (Exception e) {
1049 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001050 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001051 log.error(":getFlow FlowId:{} failed", flowId.toString());
1052 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001053 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001054 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001055 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001056 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001057
1058 //
1059 // Extract the Flow state
1060 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001061 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001062 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001063
1064 return flowPath;
1065 }
1066
1067 /**
1068 * Get all previously added flows by a specific installer for a given
1069 * data path endpoints.
1070 *
1071 * @param installerId the Caller ID of the installer of the flow to get.
1072 * @param dataPathEndpoints the data path endpoints of the flow to get.
1073 * @return the Flow Paths if found, otherwise null.
1074 */
1075 @Override
1076 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1077 DataPathEndpoints dataPathEndpoints) {
1078 //
1079 // TODO: The implementation below is not optimal:
1080 // We fetch all flows, and then return only the subset that match
1081 // the query conditions.
1082 // We should use the appropriate Titan/Gremlin query to filter-out
1083 // the flows as appropriate.
1084 //
1085 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001086 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001087
1088 if (allFlows == null) {
1089 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001090 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001091 }
1092
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001093 for (FlowPath flow : allFlows) {
1094 //
1095 // TODO: String-based comparison is sub-optimal.
1096 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001097 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001098 //
1099 if (! flow.installerId().toString().equals(installerId.toString()))
1100 continue;
1101 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1102 continue;
1103 }
1104 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1105 continue;
1106 }
1107 flowPaths.add(flow);
1108 }
1109
1110 if (flowPaths.isEmpty()) {
1111 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001112 } else {
1113 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1114 }
1115
1116 return flowPaths;
1117 }
1118
1119 /**
1120 * Get all installed flows by all installers for given data path endpoints.
1121 *
1122 * @param dataPathEndpoints the data path endpoints of the flows to get.
1123 * @return the Flow Paths if found, otherwise null.
1124 */
1125 @Override
1126 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1127 //
1128 // TODO: The implementation below is not optimal:
1129 // We fetch all flows, and then return only the subset that match
1130 // the query conditions.
1131 // We should use the appropriate Titan/Gremlin query to filter-out
1132 // the flows as appropriate.
1133 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001134 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1135 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001136
1137 if (allFlows == null) {
1138 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001139 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001140 }
1141
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001142 for (FlowPath flow : allFlows) {
1143 //
1144 // TODO: String-based comparison is sub-optimal.
1145 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001146 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001147 //
1148 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1149 continue;
1150 }
1151 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1152 continue;
1153 }
1154 flowPaths.add(flow);
1155 }
1156
1157 if (flowPaths.isEmpty()) {
1158 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001159 } else {
1160 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1161 }
1162
1163 return flowPaths;
1164 }
1165
1166 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001167 * Get summary of all installed flows by all installers in a given range
1168 *
1169 * @param flowId the data path endpoints of the flows to get.
1170 * @param maxFlows: the maximum number of flows to be returned
1171 * @return the Flow Paths if found, otherwise null.
1172 */
1173 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001174 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001175
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001176 // TODO: The implementation below is not optimal:
1177 // We fetch all flows, and then return only the subset that match
1178 // the query conditions.
1179 // We should use the appropriate Titan/Gremlin query to filter-out
1180 // the flows as appropriate.
1181 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001182 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001183
Jonathan Hart01f2d272013-04-04 20:03:46 -07001184 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1185
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001186 Collections.sort(flowPathsWithoutFlowEntries,
1187 new Comparator<IFlowPath>(){
1188 @Override
1189 public int compare(IFlowPath first, IFlowPath second) {
1190 // TODO Auto-generated method stub
1191 long result = new FlowId(first.getFlowId()).value()
1192 - new FlowId(second.getFlowId()).value();
1193 if (result > 0) return 1;
1194 else if (result < 0) return -1;
1195 else return 0;
1196 }
1197 }
1198 );
1199
Jonathan Hart01f2d272013-04-04 20:03:46 -07001200 return flowPathsWithoutFlowEntries;
1201
1202 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001203 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001204
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001205 if (allFlows == null) {
1206 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001207 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001208 }
1209
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001210 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001211
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001212 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001213 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001214
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001215 // start from desired flowId
1216 if (flow.flowId().value() < flowId.value()) {
1217 continue;
1218 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001219
1220 // Summarize by making null flow entry fields that are not relevant to report
1221 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1222 flowEntry.setFlowEntryActions(null);
1223 flowEntry.setFlowEntryMatch(null);
1224 }
1225
1226 flowPaths.add(flow);
1227 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1228 break;
1229 }
1230 }
1231
1232 if (flowPaths.isEmpty()) {
1233 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001234 } else {
1235 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1236 }
1237
1238 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001239 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001240 }
1241
1242 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001243 * Get all installed flows by all installers.
1244 *
1245 * @return the Flow Paths if found, otherwise null.
1246 */
1247 @Override
1248 public ArrayList<FlowPath> getAllFlows() {
1249 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001250 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001251
1252 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001253 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001254 log.debug("Get all FlowPaths: found FlowPaths");
1255 } else {
1256 log.debug("Get all FlowPaths: no FlowPaths found");
1257 }
1258 } catch (Exception e) {
1259 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001260 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001261 log.error(":getAllFlowPaths failed");
1262 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001263 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001264 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001265 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001266 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001267
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001268 for (IFlowPath flowObj : flowPathsObj) {
1269 //
1270 // Extract the Flow state
1271 //
1272 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001273 if (flowPath != null)
1274 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001275 }
1276
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001277 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001278
1279 return flowPaths;
1280 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001281
1282 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1283 Iterable<IFlowPath> flowPathsObj = null;
1284 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1285 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1286
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001287 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001288
Jonathan Hart01f2d272013-04-04 20:03:46 -07001289 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001290 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001291 log.debug("Get all FlowPaths: found FlowPaths");
1292 } else {
1293 log.debug("Get all FlowPaths: no FlowPaths found");
1294 }
1295 } catch (Exception e) {
1296 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001297 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001298 log.error(":getAllFlowPaths failed");
1299 }
1300 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1301 return new ArrayList<IFlowPath>(); // No Flows found
1302 }
1303
1304 for (IFlowPath flowObj : flowPathsObj){
1305 flowPathsObjArray.add(flowObj);
1306 }
1307 /*
1308 for (IFlowPath flowObj : flowPathsObj) {
1309 //
1310 // Extract the Flow state
1311 //
1312 FlowPath flowPath = extractFlowPath(flowObj);
1313 if (flowPath != null)
1314 flowPaths.add(flowPath);
1315 }
1316 */
1317
1318 //conn.endTx(Transaction.COMMIT);
1319
1320 return flowPathsObjArray;
1321 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001322
1323 /**
1324 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1325 *
1326 * @param flowObj the object to extract the Flow Path State from.
1327 * @return the extracted Flow Path State.
1328 */
1329 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001330 //
1331 // Extract the Flow state
1332 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001333 String flowIdStr = flowObj.getFlowId();
1334 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001335 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001336 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001337 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001338 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001339 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001340
1341 if ((flowIdStr == null) ||
1342 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001343 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001344 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001345 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001346 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001347 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001348 // TODO: A work-around, becauuse of some bogus database objects
1349 return null;
1350 }
1351
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001352 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001353 flowPath.setFlowId(new FlowId(flowIdStr));
1354 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001355 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001356 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001357 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001358 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001359 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001360 //
1361 // Extract the match conditions common for all Flow Entries
1362 //
1363 {
1364 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001365 String matchSrcMac = flowObj.getMatchSrcMac();
1366 if (matchSrcMac != null)
1367 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1368 String matchDstMac = flowObj.getMatchDstMac();
1369 if (matchDstMac != null)
1370 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001371 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1372 if (matchEthernetFrameType != null)
1373 match.enableEthernetFrameType(matchEthernetFrameType);
1374 Short matchVlanId = flowObj.getMatchVlanId();
1375 if (matchVlanId != null)
1376 match.enableVlanId(matchVlanId);
1377 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1378 if (matchVlanPriority != null)
1379 match.enableVlanPriority(matchVlanPriority);
1380 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1381 if (matchSrcIPv4Net != null)
1382 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1383 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1384 if (matchDstIPv4Net != null)
1385 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1386 Byte matchIpProto = flowObj.getMatchIpProto();
1387 if (matchIpProto != null)
1388 match.enableIpProto(matchIpProto);
1389 Byte matchIpToS = flowObj.getMatchIpToS();
1390 if (matchIpToS != null)
1391 match.enableIpToS(matchIpToS);
1392 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1393 if (matchSrcTcpUdpPort != null)
1394 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1395 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1396 if (matchDstTcpUdpPort != null)
1397 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1398
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001399 flowPath.setFlowEntryMatch(match);
1400 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001401 //
1402 // Extract the actions for the first Flow Entry
1403 //
1404 {
1405 String actionsStr = flowObj.getActions();
1406 if (actionsStr != null) {
1407 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1408 flowPath.setFlowEntryActions(flowEntryActions);
1409 }
1410 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001411
1412 //
1413 // Extract all Flow Entries
1414 //
1415 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1416 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001417 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1418 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001419 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001420 flowPath.dataPath().flowEntries().add(flowEntry);
1421 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001422
1423 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001424 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001425
1426 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001427 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1428 *
1429 * @param flowEntryObj the object to extract the Flow Entry State from.
1430 * @return the extracted Flow Entry State.
1431 */
1432 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1433 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1434 String switchDpidStr = flowEntryObj.getSwitchDpid();
1435 String userState = flowEntryObj.getUserState();
1436 String switchState = flowEntryObj.getSwitchState();
1437
1438 if ((flowEntryIdStr == null) ||
1439 (switchDpidStr == null) ||
1440 (userState == null) ||
1441 (switchState == null)) {
1442 // TODO: A work-around, becauuse of some bogus database objects
1443 return null;
1444 }
1445
1446 FlowEntry flowEntry = new FlowEntry();
1447 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1448 flowEntry.setDpid(new Dpid(switchDpidStr));
1449
1450 //
1451 // Extract the match conditions
1452 //
1453 FlowEntryMatch match = new FlowEntryMatch();
1454 Short matchInPort = flowEntryObj.getMatchInPort();
1455 if (matchInPort != null)
1456 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001457 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1458 if (matchSrcMac != null)
1459 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1460 String matchDstMac = flowEntryObj.getMatchDstMac();
1461 if (matchDstMac != null)
1462 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001463 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1464 if (matchEthernetFrameType != null)
1465 match.enableEthernetFrameType(matchEthernetFrameType);
1466 Short matchVlanId = flowEntryObj.getMatchVlanId();
1467 if (matchVlanId != null)
1468 match.enableVlanId(matchVlanId);
1469 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1470 if (matchVlanPriority != null)
1471 match.enableVlanPriority(matchVlanPriority);
1472 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1473 if (matchSrcIPv4Net != null)
1474 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1475 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1476 if (matchDstIPv4Net != null)
1477 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1478 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1479 if (matchIpProto != null)
1480 match.enableIpProto(matchIpProto);
1481 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1482 if (matchIpToS != null)
1483 match.enableIpToS(matchIpToS);
1484 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1485 if (matchSrcTcpUdpPort != null)
1486 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1487 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1488 if (matchDstTcpUdpPort != null)
1489 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001490 flowEntry.setFlowEntryMatch(match);
1491
1492 //
1493 // Extract the actions
1494 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001495 FlowEntryActions actions = new FlowEntryActions();
1496 String actionsStr = flowEntryObj.getActions();
1497 if (actionsStr != null)
1498 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001499 flowEntry.setFlowEntryActions(actions);
1500 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1501 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1502 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001503 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001504 //
1505 return flowEntry;
1506 }
1507
1508 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001509 * Add and maintain a shortest-path flow.
1510 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001511 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001512 *
1513 * @param flowPath the Flow Path with the endpoints and the match
1514 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001515 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001516 */
1517 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001518 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001519 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001520 // Don't do the shortest path computation here.
1521 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001522 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001523
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001524 // We need the DataPath to populate the Network MAP
1525 DataPath dataPath = new DataPath();
1526 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1527 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001528
1529 //
1530 // Prepare the computed Flow Path
1531 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001532 FlowPath computedFlowPath = new FlowPath();
1533 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1534 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001535 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001536 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001537 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001538 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001539
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001540 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001541 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001542 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001543 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001544
1545 // TODO: Mark the flow for maintenance purpose
1546
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001547 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001548 }
1549
1550 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001551 * Reconcile a flow.
1552 *
1553 * @param flowObj the flow that needs to be reconciliated.
1554 * @param newDataPath the new data path to use.
1555 * @return true on success, otherwise false.
1556 */
1557 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1558 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1559
1560 //
1561 // Set the incoming port matching and the outgoing port output
1562 // actions for each flow entry.
1563 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001564 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001565 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1566 // Set the incoming port matching
1567 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1568 flowEntry.setFlowEntryMatch(flowEntryMatch);
1569 flowEntryMatch.enableInPort(flowEntry.inPort());
1570
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001571 //
1572 // Set the actions
1573 //
1574 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1575 //
1576 // If the first Flow Entry, copy the Flow Path actions to it
1577 //
1578 if (idx == 0) {
1579 String actionsStr = flowObj.getActions();
1580 if (actionsStr != null) {
1581 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1582 for (FlowEntryAction action : flowActions.actions())
1583 flowEntryActions.addAction(action);
1584 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001585 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001586 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001587 //
1588 // Add the outgoing port output action
1589 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001590 FlowEntryAction flowEntryAction = new FlowEntryAction();
1591 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001592 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001593 }
1594
1595 //
1596 // Remove the old Flow Entries, and add the new Flow Entries
1597 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001598 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1599 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1600 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001601 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001602 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001603 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001604 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001605 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001606 }
1607
1608 //
1609 // Set the Data Path Summary
1610 //
1611 String dataPathSummaryStr = newDataPath.dataPathSummary();
1612 flowObj.setDataPathSummary(dataPathSummaryStr);
1613
1614 return true;
1615 }
1616
1617 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001618 * Reconcile all flows in a set.
1619 *
1620 * @param flowObjSet the set of flows that need to be reconciliated.
1621 */
1622 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1623 if (! flowObjSet.iterator().hasNext())
1624 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001625 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001626 }
1627
1628 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001629 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001630 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001631 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001632 * @param flowObj the flow path object for the flow entry to install.
1633 * @param flowEntryObj the flow entry object to install.
1634 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001635 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001636 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1637 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001638 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1639 if (flowEntryIdStr == null)
1640 return false;
1641 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001642 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001643 if (userState == null)
1644 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001645
1646 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001647 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001648 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001649 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1650 .getMessage(OFType.FLOW_MOD);
1651 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001652
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001653 short flowModCommand = OFFlowMod.OFPFC_ADD;
1654 if (userState.equals("FE_USER_ADD")) {
1655 flowModCommand = OFFlowMod.OFPFC_ADD;
1656 } else if (userState.equals("FE_USER_MODIFY")) {
1657 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1658 } else if (userState.equals("FE_USER_DELETE")) {
1659 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1660 } else {
1661 // Unknown user state. Ignore the entry
1662 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1663 flowEntryId.toString(), userState);
1664 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001665 }
1666
1667 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001668 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001669 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001670 // NOTE: The Flow matching conditions common for all Flow Entries are
1671 // used ONLY if a Flow Entry does NOT have the corresponding matching
1672 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001673 //
1674 OFMatch match = new OFMatch();
1675 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001676
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001677 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001678 Short matchInPort = flowEntryObj.getMatchInPort();
1679 if (matchInPort != null) {
1680 match.setInputPort(matchInPort);
1681 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1682 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001683
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001684 // Match the Source MAC address
1685 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1686 if (matchSrcMac == null)
1687 matchSrcMac = flowObj.getMatchSrcMac();
1688 if (matchSrcMac != null) {
1689 match.setDataLayerSource(matchSrcMac);
1690 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1691 }
1692
1693 // Match the Destination MAC address
1694 String matchDstMac = flowEntryObj.getMatchDstMac();
1695 if (matchDstMac == null)
1696 matchDstMac = flowObj.getMatchDstMac();
1697 if (matchDstMac != null) {
1698 match.setDataLayerDestination(matchDstMac);
1699 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1700 }
1701
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001702 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001703 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1704 if (matchEthernetFrameType == null)
1705 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1706 if (matchEthernetFrameType != null) {
1707 match.setDataLayerType(matchEthernetFrameType);
1708 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1709 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001710
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001711 // Match the VLAN ID
1712 Short matchVlanId = flowEntryObj.getMatchVlanId();
1713 if (matchVlanId == null)
1714 matchVlanId = flowObj.getMatchVlanId();
1715 if (matchVlanId != null) {
1716 match.setDataLayerVirtualLan(matchVlanId);
1717 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1718 }
1719
1720 // Match the VLAN priority
1721 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1722 if (matchVlanPriority == null)
1723 matchVlanPriority = flowObj.getMatchVlanPriority();
1724 if (matchVlanPriority != null) {
1725 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1726 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1727 }
1728
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001729 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001730 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1731 if (matchSrcIPv4Net == null)
1732 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1733 if (matchSrcIPv4Net != null) {
1734 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1735 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001736
1737 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001738 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1739 if (matchDstIPv4Net == null)
1740 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1741 if (matchDstIPv4Net != null) {
1742 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1743 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001744
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001745 // Match the IP protocol
1746 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1747 if (matchIpProto == null)
1748 matchIpProto = flowObj.getMatchIpProto();
1749 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001750 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001751 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001752 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001753
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001754 // Match the IP ToS (DSCP field, 6 bits)
1755 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1756 if (matchIpToS == null)
1757 matchIpToS = flowObj.getMatchIpToS();
1758 if (matchIpToS != null) {
1759 match.setNetworkTypeOfService(matchIpToS);
1760 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1761 }
1762
1763 // Match the Source TCP/UDP port
1764 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1765 if (matchSrcTcpUdpPort == null)
1766 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1767 if (matchSrcTcpUdpPort != null) {
1768 match.setTransportSource(matchSrcTcpUdpPort);
1769 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1770 }
1771
1772 // Match the Destination TCP/UDP port
1773 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1774 if (matchDstTcpUdpPort == null)
1775 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1776 if (matchDstTcpUdpPort != null) {
1777 match.setTransportDestination(matchDstTcpUdpPort);
1778 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001779 }
1780
1781 //
1782 // Fetch the actions
1783 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001784 Short actionOutputPort = null;
1785 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1786 int actionsLen = 0;
1787 FlowEntryActions flowEntryActions = null;
1788 String actionsStr = flowEntryObj.getActions();
1789 if (actionsStr != null)
1790 flowEntryActions = new FlowEntryActions(actionsStr);
1791 for (FlowEntryAction action : flowEntryActions.actions()) {
1792 ActionOutput actionOutput = action.actionOutput();
1793 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1794 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1795 ActionStripVlan actionStripVlan = action.actionStripVlan();
1796 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1797 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1798 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1799 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1800 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1801 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1802 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1803 ActionEnqueue actionEnqueue = action.actionEnqueue();
1804
1805 if (actionOutput != null) {
1806 actionOutputPort = actionOutput.port().value();
1807 // XXX: The max length is hard-coded for now
1808 OFActionOutput ofa =
1809 new OFActionOutput(actionOutput.port().value(),
1810 (short)0xffff);
1811 openFlowActions.add(ofa);
1812 actionsLen += ofa.getLength();
1813 }
1814
1815 if (actionSetVlanId != null) {
1816 OFActionVirtualLanIdentifier ofa =
1817 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1818 openFlowActions.add(ofa);
1819 actionsLen += ofa.getLength();
1820 }
1821
1822 if (actionSetVlanPriority != null) {
1823 OFActionVirtualLanPriorityCodePoint ofa =
1824 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1825 openFlowActions.add(ofa);
1826 actionsLen += ofa.getLength();
1827 }
1828
1829 if (actionStripVlan != null) {
1830 if (actionStripVlan.stripVlan() == true) {
1831 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1832 openFlowActions.add(ofa);
1833 actionsLen += ofa.getLength();
1834 }
1835 }
1836
1837 if (actionSetEthernetSrcAddr != null) {
1838 OFActionDataLayerSource ofa =
1839 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1840 openFlowActions.add(ofa);
1841 actionsLen += ofa.getLength();
1842 }
1843
1844 if (actionSetEthernetDstAddr != null) {
1845 OFActionDataLayerDestination ofa =
1846 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1847 openFlowActions.add(ofa);
1848 actionsLen += ofa.getLength();
1849 }
1850
1851 if (actionSetIPv4SrcAddr != null) {
1852 OFActionNetworkLayerSource ofa =
1853 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1854 openFlowActions.add(ofa);
1855 actionsLen += ofa.getLength();
1856 }
1857
1858 if (actionSetIPv4DstAddr != null) {
1859 OFActionNetworkLayerDestination ofa =
1860 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1861 openFlowActions.add(ofa);
1862 actionsLen += ofa.getLength();
1863 }
1864
1865 if (actionSetIpToS != null) {
1866 OFActionNetworkTypeOfService ofa =
1867 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1868 openFlowActions.add(ofa);
1869 actionsLen += ofa.getLength();
1870 }
1871
1872 if (actionSetTcpUdpSrcPort != null) {
1873 OFActionTransportLayerSource ofa =
1874 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1875 openFlowActions.add(ofa);
1876 actionsLen += ofa.getLength();
1877 }
1878
1879 if (actionSetTcpUdpDstPort != null) {
1880 OFActionTransportLayerDestination ofa =
1881 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1882 openFlowActions.add(ofa);
1883 actionsLen += ofa.getLength();
1884 }
1885
1886 if (actionEnqueue != null) {
1887 OFActionEnqueue ofa =
1888 new OFActionEnqueue(actionEnqueue.port().value(),
1889 actionEnqueue.queueId());
1890 openFlowActions.add(ofa);
1891 actionsLen += ofa.getLength();
1892 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001893 }
1894
1895 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1896 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1897 .setPriority(PRIORITY_DEFAULT)
1898 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1899 .setCookie(cookie)
1900 .setCommand(flowModCommand)
1901 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001902 .setActions(openFlowActions)
1903 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001904 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1905 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1906 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1907 if (actionOutputPort != null)
1908 fm.setOutPort(actionOutputPort);
1909 }
1910
1911 //
1912 // TODO: Set the following flag
1913 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1914 // See method ForwardingBase::pushRoute()
1915 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001916
1917 //
1918 // Write the message to the switch
1919 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001920 log.debug("MEASUREMENT: Installing flow entry " + userState +
1921 " into switch DPID: " +
1922 mySwitch.getStringId() +
1923 " flowEntryId: " + flowEntryId.toString() +
1924 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1925 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1926 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001927 try {
1928 messageDamper.write(mySwitch, fm, null);
1929 mySwitch.flush();
1930 //
1931 // TODO: We should use the OpenFlow Barrier mechanism
1932 // to check for errors, and update the SwitchState
1933 // for a flow entry after the Barrier message is
1934 // is received.
1935 //
1936 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1937 } catch (IOException e) {
1938 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001939 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001940 }
1941
1942 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001943 }
1944
1945 /**
1946 * Install a Flow Entry on a switch.
1947 *
1948 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001949 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001950 * @param flowEntry the flow entry to install.
1951 * @return true on success, otherwise false.
1952 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001953 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1954 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001955 //
1956 // Create the OpenFlow Flow Modification Entry to push
1957 //
1958 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1959 .getMessage(OFType.FLOW_MOD);
1960 long cookie = flowEntry.flowEntryId().value();
1961
1962 short flowModCommand = OFFlowMod.OFPFC_ADD;
1963 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1964 flowModCommand = OFFlowMod.OFPFC_ADD;
1965 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1966 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1967 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1968 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1969 } else {
1970 // Unknown user state. Ignore the entry
1971 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1972 flowEntry.flowEntryId().toString(),
1973 flowEntry.flowEntryUserState());
1974 return false;
1975 }
1976
1977 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001978 // Fetch the match conditions.
1979 //
1980 // NOTE: The Flow matching conditions common for all Flow Entries are
1981 // used ONLY if a Flow Entry does NOT have the corresponding matching
1982 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001983 //
1984 OFMatch match = new OFMatch();
1985 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001986 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1987 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1988
1989 // Match the Incoming Port
1990 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001991 if (matchInPort != null) {
1992 match.setInputPort(matchInPort.value());
1993 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1994 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001995
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001996 // Match the Source MAC address
1997 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1998 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1999 matchSrcMac = flowPathMatch.srcMac();
2000 }
2001 if (matchSrcMac != null) {
2002 match.setDataLayerSource(matchSrcMac.toString());
2003 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2004 }
2005
2006 // Match the Destination MAC address
2007 MACAddress matchDstMac = flowEntryMatch.dstMac();
2008 if ((matchDstMac == null) && (flowPathMatch != null)) {
2009 matchDstMac = flowPathMatch.dstMac();
2010 }
2011 if (matchDstMac != null) {
2012 match.setDataLayerDestination(matchDstMac.toString());
2013 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2014 }
2015
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002016 // Match the Ethernet Frame Type
2017 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2018 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2019 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2020 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002021 if (matchEthernetFrameType != null) {
2022 match.setDataLayerType(matchEthernetFrameType);
2023 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2024 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002025
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002026 // Match the VLAN ID
2027 Short matchVlanId = flowEntryMatch.vlanId();
2028 if ((matchVlanId == null) && (flowPathMatch != null)) {
2029 matchVlanId = flowPathMatch.vlanId();
2030 }
2031 if (matchVlanId != null) {
2032 match.setDataLayerVirtualLan(matchVlanId);
2033 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2034 }
2035
2036 // Match the VLAN priority
2037 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2038 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2039 matchVlanPriority = flowPathMatch.vlanPriority();
2040 }
2041 if (matchVlanPriority != null) {
2042 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2043 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2044 }
2045
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002046 // Match the Source IPv4 Network prefix
2047 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2048 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2049 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2050 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002051 if (matchSrcIPv4Net != null) {
2052 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2053 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002054
2055 // Natch the Destination IPv4 Network prefix
2056 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2057 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2058 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2059 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002060 if (matchDstIPv4Net != null) {
2061 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2062 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002063
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002064 // Match the IP protocol
2065 Byte matchIpProto = flowEntryMatch.ipProto();
2066 if ((matchIpProto == null) && (flowPathMatch != null)) {
2067 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002068 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002069 if (matchIpProto != null) {
2070 match.setNetworkProtocol(matchIpProto);
2071 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002072 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002073
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002074 // Match the IP ToS (DSCP field, 6 bits)
2075 Byte matchIpToS = flowEntryMatch.ipToS();
2076 if ((matchIpToS == null) && (flowPathMatch != null)) {
2077 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002078 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002079 if (matchIpToS != null) {
2080 match.setNetworkTypeOfService(matchIpToS);
2081 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2082 }
2083
2084 // Match the Source TCP/UDP port
2085 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2086 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2087 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2088 }
2089 if (matchSrcTcpUdpPort != null) {
2090 match.setTransportSource(matchSrcTcpUdpPort);
2091 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2092 }
2093
2094 // Match the Destination TCP/UDP port
2095 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2096 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2097 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2098 }
2099 if (matchDstTcpUdpPort != null) {
2100 match.setTransportDestination(matchDstTcpUdpPort);
2101 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002102 }
2103
2104 //
2105 // Fetch the actions
2106 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002107 Short actionOutputPort = null;
2108 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2109 int actionsLen = 0;
2110 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002111 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002112 for (FlowEntryAction action : flowEntryActions.actions()) {
2113 ActionOutput actionOutput = action.actionOutput();
2114 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2115 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2116 ActionStripVlan actionStripVlan = action.actionStripVlan();
2117 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2118 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2119 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2120 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2121 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2122 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2123 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2124 ActionEnqueue actionEnqueue = action.actionEnqueue();
2125
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002126 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002127 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002128 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002129 OFActionOutput ofa =
2130 new OFActionOutput(actionOutput.port().value(),
2131 (short)0xffff);
2132 openFlowActions.add(ofa);
2133 actionsLen += ofa.getLength();
2134 }
2135
2136 if (actionSetVlanId != null) {
2137 OFActionVirtualLanIdentifier ofa =
2138 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2139 openFlowActions.add(ofa);
2140 actionsLen += ofa.getLength();
2141 }
2142
2143 if (actionSetVlanPriority != null) {
2144 OFActionVirtualLanPriorityCodePoint ofa =
2145 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2146 openFlowActions.add(ofa);
2147 actionsLen += ofa.getLength();
2148 }
2149
2150 if (actionStripVlan != null) {
2151 if (actionStripVlan.stripVlan() == true) {
2152 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2153 openFlowActions.add(ofa);
2154 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002155 }
2156 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002157
2158 if (actionSetEthernetSrcAddr != null) {
2159 OFActionDataLayerSource ofa =
2160 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2161 openFlowActions.add(ofa);
2162 actionsLen += ofa.getLength();
2163 }
2164
2165 if (actionSetEthernetDstAddr != null) {
2166 OFActionDataLayerDestination ofa =
2167 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2168 openFlowActions.add(ofa);
2169 actionsLen += ofa.getLength();
2170 }
2171
2172 if (actionSetIPv4SrcAddr != null) {
2173 OFActionNetworkLayerSource ofa =
2174 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2175 openFlowActions.add(ofa);
2176 actionsLen += ofa.getLength();
2177 }
2178
2179 if (actionSetIPv4DstAddr != null) {
2180 OFActionNetworkLayerDestination ofa =
2181 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2182 openFlowActions.add(ofa);
2183 actionsLen += ofa.getLength();
2184 }
2185
2186 if (actionSetIpToS != null) {
2187 OFActionNetworkTypeOfService ofa =
2188 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2189 openFlowActions.add(ofa);
2190 actionsLen += ofa.getLength();
2191 }
2192
2193 if (actionSetTcpUdpSrcPort != null) {
2194 OFActionTransportLayerSource ofa =
2195 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2196 openFlowActions.add(ofa);
2197 actionsLen += ofa.getLength();
2198 }
2199
2200 if (actionSetTcpUdpDstPort != null) {
2201 OFActionTransportLayerDestination ofa =
2202 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2203 openFlowActions.add(ofa);
2204 actionsLen += ofa.getLength();
2205 }
2206
2207 if (actionEnqueue != null) {
2208 OFActionEnqueue ofa =
2209 new OFActionEnqueue(actionEnqueue.port().value(),
2210 actionEnqueue.queueId());
2211 openFlowActions.add(ofa);
2212 actionsLen += ofa.getLength();
2213 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002214 }
2215
2216 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2217 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2218 .setPriority(PRIORITY_DEFAULT)
2219 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2220 .setCookie(cookie)
2221 .setCommand(flowModCommand)
2222 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002223 .setActions(openFlowActions)
2224 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2225 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2226 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2227 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2228 if (actionOutputPort != null)
2229 fm.setOutPort(actionOutputPort);
2230 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002231
2232 //
2233 // TODO: Set the following flag
2234 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2235 // See method ForwardingBase::pushRoute()
2236 //
2237
2238 //
2239 // Write the message to the switch
2240 //
2241 try {
2242 messageDamper.write(mySwitch, fm, null);
2243 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002244 //
2245 // TODO: We should use the OpenFlow Barrier mechanism
2246 // to check for errors, and update the SwitchState
2247 // for a flow entry after the Barrier message is
2248 // is received.
2249 //
2250 // TODO: The FlowEntry Object in Titan should be set
2251 // to FE_SWITCH_UPDATED.
2252 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002253 } catch (IOException e) {
2254 log.error("Failure writing flow mod from network map", e);
2255 return false;
2256 }
2257 return true;
2258 }
2259
2260 /**
2261 * Remove a Flow Entry from a switch.
2262 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002263 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002264 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002265 * @param flowEntry the flow entry to remove.
2266 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002267 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002268 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2269 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002270 //
2271 // The installFlowEntry() method implements both installation
2272 // and removal of flow entries.
2273 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002274 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002275 }
2276
2277 /**
2278 * Install a Flow Entry on a remote controller.
2279 *
2280 * TODO: We need it now: Jono
2281 * - For now it will make a REST call to the remote controller.
2282 * - Internally, it needs to know the name of the remote controller.
2283 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002284 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002285 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002286 * @return true on success, otherwise false.
2287 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002288 public boolean installRemoteFlowEntry(FlowPath flowPath,
2289 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002290 // TODO: We need it now: Jono
2291 // - For now it will make a REST call to the remote controller.
2292 // - Internally, it needs to know the name of the remote controller.
2293 return true;
2294 }
2295
2296 /**
2297 * Remove a flow entry on a remote controller.
2298 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002299 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002300 * @param flowEntry the flow entry to remove.
2301 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002302 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002303 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2304 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002305 //
2306 // The installRemoteFlowEntry() method implements both installation
2307 // and removal of flow entries.
2308 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002309 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002310 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002311}