blob: 89415f071575a9d5f9e7608dae1d93a8e7d13d37 [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()) {
131 return;
132 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700133 LinkedList<IFlowEntry> addFlowEntries =
134 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000135 LinkedList<IFlowEntry> deleteFlowEntries =
136 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700137
138 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700139 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700140 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700141 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700142 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000143 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700144 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700145 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700146 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000147
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000148 String dpidStr = flowEntryObj.getSwitchDpid();
149 if (dpidStr == null)
150 continue;
151 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800152 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000153 if (mySwitch == null)
154 continue; // Ignore the entry: not my switch
155
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700156 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700157 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700158 if (flowObj == null)
159 continue; // Should NOT happen
160 if (flowObj.getFlowId() == null)
161 continue; // Invalid entry
162
163 //
164 // NOTE: For now we process the DELETE before the ADD
165 // to cover the more common scenario.
166 // TODO: This is error prone and needs to be fixed!
167 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000168 String userState = flowEntryObj.getUserState();
169 if (userState == null)
170 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700171 if (userState.equals("FE_USER_DELETE")) {
172 // An entry that needs to be deleted.
173 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700174 installFlowEntry(mySwitch, flowObj, flowEntryObj);
175 } else {
176 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700177 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700178 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700179 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700180 // TODO: Commented-out for now
181 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700182 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700183 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700184 processed_measurement_flow = true;
185 }
186 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700187 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700188 }
189
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700190 //
191 // Process the Flow Entries that need to be added
192 //
193 for (IFlowEntry flowEntryObj : addFlowEntries) {
194 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700195 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700196 if (flowObj == null)
197 continue; // Should NOT happen
198 if (flowObj.getFlowId() == null)
199 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700200
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700201 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700202 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000203 if (mySwitch == null)
204 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700205 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800206 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000207
208 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000209 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700210 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000211 //
212 // TODO: We should use the OpenFlow Barrier mechanism
213 // to check for errors, and delete the Flow Entries after the
214 // Barrier message is received.
215 //
216 while (! deleteFlowEntries.isEmpty()) {
217 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
218 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700219 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000220 if (flowObj == null) {
221 log.debug("Did not find FlowPath to be deleted");
222 continue;
223 }
224 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700225 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000226 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700227
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700228 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700229
230 if (processed_measurement_flow) {
231 long estimatedTime =
232 System.nanoTime() - modifiedMeasurementFlowTime;
233 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
234 (double)estimatedTime / 1000000000 + " sec";
235 log.debug(logMsg);
236 }
237
238 long estimatedTime = System.nanoTime() - startTime;
239 double rate = 0.0;
240 if (estimatedTime > 0)
241 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
242 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
243 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
244 counterMyNotUpdatedFlowEntries + " in " +
245 (double)estimatedTime / 1000000000 + " sec: " +
246 rate + " paths/s";
247 log.debug(logMsg);
248 }
249 };
250
251 final Runnable shortestPathReconcile = new Runnable() {
252 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700253 try {
254 runImpl();
255 } catch (Exception e) {
256 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700257 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700258 return;
259 }
260 }
261
262 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700263 long startTime = System.nanoTime();
264 int counterAllFlowPaths = 0;
265 int counterMyFlowPaths = 0;
266
267 if (floodlightProvider == null) {
268 log.debug("FloodlightProvider service not found!");
269 return;
270 }
271 Map<Long, IOFSwitch> mySwitches =
272 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700273 if (mySwitches.isEmpty()) {
274 return;
275 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700276 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
277
278 boolean processed_measurement_flow = false;
279
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700280 //
281 // Fetch and recompute the Shortest Path for those
282 // Flow Paths this controller is responsible for.
283 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000284 Map<Long, ?> shortestPathTopo =
285 topoRouteService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700286 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700287 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700288 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700289 if (flowPathObj == null)
290 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700291
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700292 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000293 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700294 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700295 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700296 //
297 // Use the source DPID as a heuristic to decide
298 // which controller is responsible for maintaining the
299 // shortest path.
300 // NOTE: This heuristic is error-prone: if the switch
301 // goes away and no controller is responsible for that
302 // switch, then the original Flow Path is not cleaned-up
303 //
304 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
305 if (mySwitch == null)
306 continue; // Ignore: not my responsibility
307
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700308 // Test the Data Path Summary string
309 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
310 if (dataPathSummaryStr == null)
311 continue; // Could be invalid entry?
312 if (dataPathSummaryStr.isEmpty())
313 continue; // No need to maintain this flow
314
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000315 //
316 // Test whether we need to complete the Flow cleanup,
317 // if the Flow has been deleted by the user.
318 //
319 String flowUserState = flowPathObj.getUserState();
320 if ((flowUserState != null)
321 && flowUserState.equals("FE_USER_DELETE")) {
322 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
323 boolean empty = true; // TODO: an ugly hack
324 for (IFlowEntry flowEntryObj : flowEntries) {
325 empty = false;
326 break;
327 }
328 if (empty)
329 deleteFlows.add(flowPathObj);
330 }
331
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000332 // Fetch the fields needed to recompute the shortest path
333 Short srcPortShort = flowPathObj.getSrcPort();
334 String dstDpidStr = flowPathObj.getDstSwitch();
335 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700336 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000337 if ((srcPortShort == null) ||
338 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700339 (dstPortShort == null) ||
340 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000341 continue;
342 }
343
344 Port srcPort = new Port(srcPortShort);
345 Dpid dstDpid = new Dpid(dstDpidStr);
346 Port dstPort = new Port(dstPortShort);
347 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
348 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700349 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000350
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700351 counterMyFlowPaths++;
352
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700353 //
354 // NOTE: Using here the regular getShortestPath() method
355 // won't work here, because that method calls internally
356 // "conn.endTx(Transaction.COMMIT)", and that will
357 // invalidate all handlers to the Titan database.
358 // If we want to experiment with calling here
359 // getShortestPath(), we need to refactor that code
360 // to avoid closing the transaction.
361 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700362 DataPath dataPath =
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000363 topoRouteService.getTopoShortestPath(shortestPathTopo,
364 srcSwitchPort,
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700365 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000366 if (dataPath == null) {
367 // We need the DataPath to compare the paths
368 dataPath = new DataPath();
369 dataPath.setSrcPort(srcSwitchPort);
370 dataPath.setDstPort(dstSwitchPort);
371 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700372 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000373
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700374 String newDataPathSummaryStr = dataPath.dataPathSummary();
375 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
376 continue; // Nothing changed
377
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700378 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700379 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000380
381 //
382 // Delete all leftover Flows marked for deletion from the
383 // Network MAP.
384 //
385 while (! deleteFlows.isEmpty()) {
386 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700387 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000388 }
389
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000390 topoRouteService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700391
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700392 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700393
394 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700395 long estimatedTime =
396 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700397 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
398 (double)estimatedTime / 1000000000 + " sec";
399 log.debug(logMsg);
400 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700401
402 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700403 double rate = 0.0;
404 if (estimatedTime > 0)
405 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700406 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700407 counterAllFlowPaths + " MyFlowPaths: " +
408 counterMyFlowPaths + " in " +
409 (double)estimatedTime / 1000000000 + " sec: " +
410 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700411 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800412 }
413 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700414
Jonathan Hart50a94982013-04-10 14:49:51 -0700415 //final ScheduledFuture<?> mapReaderHandle =
416 //mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800417
Jonathan Hart50a94982013-04-10 14:49:51 -0700418 //final ScheduledFuture<?> shortestPathReconcileHandle =
419 //shortestPathReconcileScheduler.scheduleAtFixedRate(shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700420
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800421 @Override
422 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700423 op = new GraphDBOperation(conf);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700424 topoRouteService = new TopoRouteService(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800425 }
426
427 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700428 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800429 }
430
431 @Override
432 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700433 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800434 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800435
436 @Override
437 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
438 Collection<Class<? extends IFloodlightService>> l =
439 new ArrayList<Class<? extends IFloodlightService>>();
440 l.add(IFlowService.class);
441 return l;
442 }
443
444 @Override
445 public Map<Class<? extends IFloodlightService>, IFloodlightService>
446 getServiceImpls() {
447 Map<Class<? extends IFloodlightService>,
448 IFloodlightService> m =
449 new HashMap<Class<? extends IFloodlightService>,
450 IFloodlightService>();
451 m.put(IFlowService.class, this);
452 return m;
453 }
454
455 @Override
456 public Collection<Class<? extends IFloodlightService>>
457 getModuleDependencies() {
458 Collection<Class<? extends IFloodlightService>> l =
459 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800460 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800461 l.add(IRestApiService.class);
462 return l;
463 }
464
465 @Override
466 public void init(FloodlightModuleContext context)
467 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700468 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800469 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800470 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800471 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
472 EnumSet.of(OFType.FLOW_MOD),
473 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700474
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800475 // TODO: An ugly hack!
476 String conf = "/tmp/cassandra.titan";
477 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700478
479 mapReaderScheduler = Executors.newScheduledThreadPool(1);
480 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800481 }
482
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700483 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000484 //
485 // Generate the next Flow Entry ID.
486 // NOTE: For now, the higher 32 bits are random, and
487 // the lower 32 bits are sequential.
488 // In the future, we need a better allocation mechanism.
489 //
490 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
491 nextFlowEntryIdPrefix = randomGenerator.nextInt();
492 nextFlowEntryIdSuffix = 0;
493 } else {
494 nextFlowEntryIdSuffix++;
495 }
496 long result = (long)nextFlowEntryIdPrefix << 32;
497 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
498 return result;
499 }
500
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800501 @Override
502 public void startUp(FloodlightModuleContext context) {
Jonathan Hart50a94982013-04-10 14:49:51 -0700503 restApi.addRestletRoutable(new FlowWebRoutable());
504
505 // Initialize the Flow Entry ID generator
506 nextFlowEntryIdPrefix = randomGenerator.nextInt();
507
508 mapReaderScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200509 mapReader, 3, 3, TimeUnit.SECONDS);
Jonathan Hart50a94982013-04-10 14:49:51 -0700510 shortestPathReconcileScheduler.scheduleAtFixedRate(
Jonathan Hartd1f23252013-06-13 15:17:05 +1200511 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800512 }
513
514 /**
515 * Add a flow.
516 *
517 * Internally, ONOS will automatically register the installer for
518 * receiving Flow Path Notifications for that path.
519 *
520 * @param flowPath the Flow Path to install.
521 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700522 * @param dataPathSummaryStr the data path summary string if the added
523 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800524 * @return true on success, otherwise false.
525 */
526 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700527 public boolean addFlow(FlowPath flowPath, FlowId flowId,
528 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700529 /*
530 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700531 if (flowPath.flowId().value() == measurementFlowId) {
532 modifiedMeasurementFlowTime = System.nanoTime();
533 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700534 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800535
536 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000537 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800538 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700539 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800540 != null) {
541 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
542 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000543 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800544 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700545 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800546 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
547 flowPath.flowId().toString());
548 }
549 } catch (Exception e) {
550 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700551 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000552
553 StringWriter sw = new StringWriter();
554 e.printStackTrace(new PrintWriter(sw));
555 String stacktrace = sw.toString();
556
557 log.error(":addFlow FlowId:{} failed: {}",
558 flowPath.flowId().toString(),
559 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800560 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700561 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000562 log.error(":addFlow FlowId:{} failed: Flow object not created",
563 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700564 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800565 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700566 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800567
568 //
569 // Set the Flow key:
570 // - flowId
571 //
572 flowObj.setFlowId(flowPath.flowId().toString());
573 flowObj.setType("flow");
574
575 //
576 // Set the Flow attributes:
577 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700578 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800579 // - flowPath.dataPath().srcPort()
580 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700581 // - flowPath.matchSrcMac()
582 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700583 // - flowPath.matchEthernetFrameType()
584 // - flowPath.matchVlanId()
585 // - flowPath.matchVlanPriority()
586 // - flowPath.matchSrcIPv4Net()
587 // - flowPath.matchDstIPv4Net()
588 // - flowPath.matchIpProto()
589 // - flowPath.matchIpToS()
590 // - flowPath.matchSrcTcpUdpPort()
591 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700592 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800593 //
594 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700595 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800596 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
597 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
598 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
599 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700600 if (flowPath.flowEntryMatch().matchSrcMac()) {
601 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
602 }
603 if (flowPath.flowEntryMatch().matchDstMac()) {
604 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
605 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700606 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
607 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
608 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700609 if (flowPath.flowEntryMatch().matchVlanId()) {
610 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
611 }
612 if (flowPath.flowEntryMatch().matchVlanPriority()) {
613 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
614 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700615 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
616 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
617 }
618 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
619 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
620 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700621 if (flowPath.flowEntryMatch().matchIpProto()) {
622 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700623 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700624 if (flowPath.flowEntryMatch().matchIpToS()) {
625 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
626 }
627 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
628 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
629 }
630 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
631 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700632 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700633 if (! flowPath.flowEntryActions().actions().isEmpty()) {
634 flowObj.setActions(flowPath.flowEntryActions().toString());
635 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800636
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700637 if (dataPathSummaryStr != null) {
638 flowObj.setDataPathSummary(dataPathSummaryStr);
639 } else {
640 flowObj.setDataPathSummary("");
641 }
642
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000643 if (found)
644 flowObj.setUserState("FE_USER_MODIFY");
645 else
646 flowObj.setUserState("FE_USER_ADD");
647
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800648 // Flow edges:
649 // HeadFE
650
651
652 //
653 // Flow Entries:
654 // flowPath.dataPath().flowEntries()
655 //
656 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700657 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700658 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800659 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700660 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800661 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700662 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800663
664 //
665 // TODO: We need a proper Flow ID allocation mechanism.
666 //
667 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700668
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800669 return true;
670 }
671
672 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700673 * Add a flow entry to the Network MAP.
674 *
675 * @param flowObj the corresponding Flow Path object for the Flow Entry.
676 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700677 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700678 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700679 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700680 // Flow edges
681 // HeadFE (TODO)
682
683 //
684 // Assign the FlowEntry ID.
685 //
686 if ((flowEntry.flowEntryId() == null) ||
687 (flowEntry.flowEntryId().value() == 0)) {
688 long id = getNextFlowEntryId();
689 flowEntry.setFlowEntryId(new FlowEntryId(id));
690 }
691
692 IFlowEntry flowEntryObj = null;
693 boolean found = false;
694 try {
695 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700696 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700697 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
698 flowEntry.flowEntryId().toString());
699 found = true;
700 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700701 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700702 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
703 flowEntry.flowEntryId().toString());
704 }
705 } catch (Exception e) {
706 log.error(":addFlow FlowEntryId:{} failed",
707 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700708 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700709 }
710 if (flowEntryObj == null) {
711 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
712 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700713 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700714 }
715
716 //
717 // Set the Flow Entry key:
718 // - flowEntry.flowEntryId()
719 //
720 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
721 flowEntryObj.setType("flow_entry");
722
723 //
724 // Set the Flow Entry Edges and attributes:
725 // - Switch edge
726 // - InPort edge
727 // - OutPort edge
728 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700729 // - flowEntry.dpid()
730 // - flowEntry.flowEntryUserState()
731 // - flowEntry.flowEntrySwitchState()
732 // - flowEntry.flowEntryErrorState()
733 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700734 // - flowEntry.matchSrcMac()
735 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700736 // - flowEntry.matchEthernetFrameType()
737 // - flowEntry.matchVlanId()
738 // - flowEntry.matchVlanPriority()
739 // - flowEntry.matchSrcIPv4Net()
740 // - flowEntry.matchDstIPv4Net()
741 // - flowEntry.matchIpProto()
742 // - flowEntry.matchIpToS()
743 // - flowEntry.matchSrcTcpUdpPort()
744 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700745 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700746 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700747 //
748 ISwitchObject sw =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700749 op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700750 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
751 flowEntryObj.setSwitch(sw);
752 if (flowEntry.flowEntryMatch().matchInPort()) {
753 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700754 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700755 flowEntry.flowEntryMatch().inPort().value());
756 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
757 flowEntryObj.setInPort(inport);
758 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700759 if (flowEntry.flowEntryMatch().matchSrcMac()) {
760 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
761 }
762 if (flowEntry.flowEntryMatch().matchDstMac()) {
763 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
764 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700765 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
766 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
767 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700768 if (flowEntry.flowEntryMatch().matchVlanId()) {
769 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
770 }
771 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
772 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
773 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700774 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
775 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
776 }
777 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
778 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
779 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700780 if (flowEntry.flowEntryMatch().matchIpProto()) {
781 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700782 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700783 if (flowEntry.flowEntryMatch().matchIpToS()) {
784 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
785 }
786 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
787 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
788 }
789 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
790 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700791 }
792
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700793 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700794 if (fa.actionOutput() != null) {
795 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700796 op.searchPort(flowEntry.dpid().toString(),
797 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700798 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700799 flowEntryObj.setOutPort(outport);
800 }
801 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700802 if (! flowEntry.flowEntryActions().isEmpty()) {
803 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
804 }
805
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700806 // TODO: Hacks with hard-coded state names!
807 if (found)
808 flowEntryObj.setUserState("FE_USER_MODIFY");
809 else
810 flowEntryObj.setUserState("FE_USER_ADD");
811 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
812 //
813 // TODO: Take care of the FlowEntryErrorState.
814 //
815
816 // Flow Entries edges:
817 // Flow
818 // NextFE (TODO)
819 if (! found) {
820 flowObj.addFlowEntry(flowEntryObj);
821 flowEntryObj.setFlow(flowObj);
822 }
823
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700824 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700825 }
826
827 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000828 * Delete all previously added flows.
829 *
830 * @return true on success, otherwise false.
831 */
832 @Override
833 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000834 List<Thread> threads = new LinkedList<Thread>();
835 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
836 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000837
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000838 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700839 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000840 for (IFlowPath flowPathObj : allFlowPaths) {
841 if (flowPathObj == null)
842 continue;
843 String flowIdStr = flowPathObj.getFlowId();
844 if (flowIdStr == null)
845 continue;
846 FlowId flowId = new FlowId(flowIdStr);
847 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000848 }
849
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000850 // Delete all flows one-by-one
851 for (FlowId flowId : concurrentAllFlowIds)
852 deleteFlow(flowId);
853
854 /*
855 * TODO: A faster mechanism to delete the Flow Paths by using
856 * a number of threads. Commented-out for now.
857 */
858 /*
859 //
860 // Create the threads to delete the Flow Paths
861 //
862 for (int i = 0; i < 10; i++) {
863 Thread thread = new Thread(new Runnable() {
864 @Override
865 public void run() {
866 while (true) {
867 FlowId flowId = concurrentAllFlowIds.poll();
868 if (flowId == null)
869 return;
870 deleteFlow(flowId);
871 }
872 }}, "Delete All Flow Paths");
873 threads.add(thread);
874 }
875
876 // Start processing
877 for (Thread thread : threads) {
878 thread.start();
879 }
880
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000881 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000882 for (Thread thread : threads) {
883 try {
884 thread.join();
885 } catch (InterruptedException e) {
886 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
887 }
888 }
889 */
890
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000891 return true;
892 }
893
894 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800895 * Delete a previously added flow.
896 *
897 * @param flowId the Flow ID of the flow to delete.
898 * @return true on success, otherwise false.
899 */
900 @Override
901 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700902 /*
903 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700904 if (flowId.value() == measurementFlowId) {
905 modifiedMeasurementFlowTime = System.nanoTime();
906 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700907 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700908
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800909 IFlowPath flowObj = null;
910 //
911 // We just mark the entries for deletion,
912 // and let the switches remove each individual entry after
913 // it has been removed from the switches.
914 //
915 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700916 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800917 != null) {
918 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
919 flowId.toString());
920 } else {
921 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
922 flowId.toString());
923 }
924 } catch (Exception e) {
925 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700926 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800927 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
928 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700929 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700930 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800931 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700932 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800933
934 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000935 // Find and mark for deletion all Flow Entries,
936 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800937 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000938 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800939 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
940 boolean empty = true; // TODO: an ugly hack
941 for (IFlowEntry flowEntryObj : flowEntries) {
942 empty = false;
943 // flowObj.removeFlowEntry(flowEntryObj);
944 // conn.utils().removeFlowEntry(conn, flowEntryObj);
945 flowEntryObj.setUserState("FE_USER_DELETE");
946 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
947 }
948 // Remove from the database empty flows
949 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700950 op.removeFlowPath(flowObj);
951 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800952
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800953 return true;
954 }
955
956 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000957 * Clear the state for all previously added flows.
958 *
959 * @return true on success, otherwise false.
960 */
961 @Override
962 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000963 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000964
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000965 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700966 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000967 for (IFlowPath flowPathObj : allFlowPaths) {
968 if (flowPathObj == null)
969 continue;
970 String flowIdStr = flowPathObj.getFlowId();
971 if (flowIdStr == null)
972 continue;
973 FlowId flowId = new FlowId(flowIdStr);
974 allFlowIds.add(flowId);
975 }
976
977 // Clear all flows one-by-one
978 for (FlowId flowId : allFlowIds) {
979 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000980 }
981
982 return true;
983 }
984
985 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700986 * Clear the state for a previously added flow.
987 *
988 * @param flowId the Flow ID of the flow to clear.
989 * @return true on success, otherwise false.
990 */
991 @Override
992 public boolean clearFlow(FlowId flowId) {
993 IFlowPath flowObj = null;
994 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700995 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700996 != null) {
997 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
998 flowId.toString());
999 } else {
1000 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
1001 flowId.toString());
1002 }
1003 } catch (Exception e) {
1004 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001005 op.rollback();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001006 log.error(":clearFlow FlowId:{} failed", flowId.toString());
1007 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001008 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001009 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001010 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001011 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001012
1013 //
1014 // Remove all Flow Entries
1015 //
1016 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1017 for (IFlowEntry flowEntryObj : flowEntries) {
1018 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001019 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001020 }
1021 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001022 op.removeFlowPath(flowObj);
1023 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001024
1025 return true;
1026 }
1027
1028 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001029 * Get a previously added flow.
1030 *
1031 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001032 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001033 */
1034 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001035 public FlowPath getFlow(FlowId flowId) {
1036 IFlowPath flowObj = null;
1037 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001038 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001039 != null) {
1040 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1041 flowId.toString());
1042 } else {
1043 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1044 flowId.toString());
1045 }
1046 } catch (Exception e) {
1047 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001048 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001049 log.error(":getFlow FlowId:{} failed", flowId.toString());
1050 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001051 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001052 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001053 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001054 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001055
1056 //
1057 // Extract the Flow state
1058 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001059 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001060 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001061
1062 return flowPath;
1063 }
1064
1065 /**
1066 * Get all previously added flows by a specific installer for a given
1067 * data path endpoints.
1068 *
1069 * @param installerId the Caller ID of the installer of the flow to get.
1070 * @param dataPathEndpoints the data path endpoints of the flow to get.
1071 * @return the Flow Paths if found, otherwise null.
1072 */
1073 @Override
1074 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1075 DataPathEndpoints dataPathEndpoints) {
1076 //
1077 // TODO: The implementation below is not optimal:
1078 // We fetch all flows, and then return only the subset that match
1079 // the query conditions.
1080 // We should use the appropriate Titan/Gremlin query to filter-out
1081 // the flows as appropriate.
1082 //
1083 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001084 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001085
1086 if (allFlows == null) {
1087 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001088 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001089 }
1090
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001091 for (FlowPath flow : allFlows) {
1092 //
1093 // TODO: String-based comparison is sub-optimal.
1094 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001095 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001096 //
1097 if (! flow.installerId().toString().equals(installerId.toString()))
1098 continue;
1099 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1100 continue;
1101 }
1102 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1103 continue;
1104 }
1105 flowPaths.add(flow);
1106 }
1107
1108 if (flowPaths.isEmpty()) {
1109 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001110 } else {
1111 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1112 }
1113
1114 return flowPaths;
1115 }
1116
1117 /**
1118 * Get all installed flows by all installers for given data path endpoints.
1119 *
1120 * @param dataPathEndpoints the data path endpoints of the flows to get.
1121 * @return the Flow Paths if found, otherwise null.
1122 */
1123 @Override
1124 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1125 //
1126 // TODO: The implementation below is not optimal:
1127 // We fetch all flows, and then return only the subset that match
1128 // the query conditions.
1129 // We should use the appropriate Titan/Gremlin query to filter-out
1130 // the flows as appropriate.
1131 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001132 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1133 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001134
1135 if (allFlows == null) {
1136 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001137 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001138 }
1139
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001140 for (FlowPath flow : allFlows) {
1141 //
1142 // TODO: String-based comparison is sub-optimal.
1143 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001144 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001145 //
1146 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1147 continue;
1148 }
1149 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1150 continue;
1151 }
1152 flowPaths.add(flow);
1153 }
1154
1155 if (flowPaths.isEmpty()) {
1156 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001157 } else {
1158 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1159 }
1160
1161 return flowPaths;
1162 }
1163
1164 /**
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001165 * Get summary of all installed flows by all installers in a given range
1166 *
1167 * @param flowId the data path endpoints of the flows to get.
1168 * @param maxFlows: the maximum number of flows to be returned
1169 * @return the Flow Paths if found, otherwise null.
1170 */
1171 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001172 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001173
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001174 // TODO: The implementation below is not optimal:
1175 // We fetch all flows, and then return only the subset that match
1176 // the query conditions.
1177 // We should use the appropriate Titan/Gremlin query to filter-out
1178 // the flows as appropriate.
1179 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001180 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001181
Jonathan Hart01f2d272013-04-04 20:03:46 -07001182 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1183
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001184 Collections.sort(flowPathsWithoutFlowEntries,
1185 new Comparator<IFlowPath>(){
1186 @Override
1187 public int compare(IFlowPath first, IFlowPath second) {
1188 // TODO Auto-generated method stub
1189 long result = new FlowId(first.getFlowId()).value()
1190 - new FlowId(second.getFlowId()).value();
1191 if (result > 0) return 1;
1192 else if (result < 0) return -1;
1193 else return 0;
1194 }
1195 }
1196 );
1197
Jonathan Hart01f2d272013-04-04 20:03:46 -07001198 return flowPathsWithoutFlowEntries;
1199
1200 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001201 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001202
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001203 if (allFlows == null) {
1204 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001205 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001206 }
1207
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001208 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001209
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001210 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001211 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001212
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001213 // start from desired flowId
1214 if (flow.flowId().value() < flowId.value()) {
1215 continue;
1216 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001217
1218 // Summarize by making null flow entry fields that are not relevant to report
1219 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1220 flowEntry.setFlowEntryActions(null);
1221 flowEntry.setFlowEntryMatch(null);
1222 }
1223
1224 flowPaths.add(flow);
1225 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1226 break;
1227 }
1228 }
1229
1230 if (flowPaths.isEmpty()) {
1231 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001232 } else {
1233 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1234 }
1235
1236 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001237 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001238 }
1239
1240 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001241 * Get all installed flows by all installers.
1242 *
1243 * @return the Flow Paths if found, otherwise null.
1244 */
1245 @Override
1246 public ArrayList<FlowPath> getAllFlows() {
1247 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001248 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001249
1250 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001251 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001252 log.debug("Get all FlowPaths: found FlowPaths");
1253 } else {
1254 log.debug("Get all FlowPaths: no FlowPaths found");
1255 }
1256 } catch (Exception e) {
1257 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001258 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001259 log.error(":getAllFlowPaths failed");
1260 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001261 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001262 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001263 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001264 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001265
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001266 for (IFlowPath flowObj : flowPathsObj) {
1267 //
1268 // Extract the Flow state
1269 //
1270 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001271 if (flowPath != null)
1272 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001273 }
1274
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001275 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001276
1277 return flowPaths;
1278 }
Jonathan Hart01f2d272013-04-04 20:03:46 -07001279
1280 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries(){
1281 Iterable<IFlowPath> flowPathsObj = null;
1282 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
1283 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1284
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001285 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001286
Jonathan Hart01f2d272013-04-04 20:03:46 -07001287 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001288 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001289 log.debug("Get all FlowPaths: found FlowPaths");
1290 } else {
1291 log.debug("Get all FlowPaths: no FlowPaths found");
1292 }
1293 } catch (Exception e) {
1294 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001295 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001296 log.error(":getAllFlowPaths failed");
1297 }
1298 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1299 return new ArrayList<IFlowPath>(); // No Flows found
1300 }
1301
1302 for (IFlowPath flowObj : flowPathsObj){
1303 flowPathsObjArray.add(flowObj);
1304 }
1305 /*
1306 for (IFlowPath flowObj : flowPathsObj) {
1307 //
1308 // Extract the Flow state
1309 //
1310 FlowPath flowPath = extractFlowPath(flowObj);
1311 if (flowPath != null)
1312 flowPaths.add(flowPath);
1313 }
1314 */
1315
1316 //conn.endTx(Transaction.COMMIT);
1317
1318 return flowPathsObjArray;
1319 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001320
1321 /**
1322 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1323 *
1324 * @param flowObj the object to extract the Flow Path State from.
1325 * @return the extracted Flow Path State.
1326 */
1327 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001328 //
1329 // Extract the Flow state
1330 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001331 String flowIdStr = flowObj.getFlowId();
1332 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001333 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001334 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001335 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001336 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001337 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001338
1339 if ((flowIdStr == null) ||
1340 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001341 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001342 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001343 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001344 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001345 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001346 // TODO: A work-around, becauuse of some bogus database objects
1347 return null;
1348 }
1349
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001350 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001351 flowPath.setFlowId(new FlowId(flowIdStr));
1352 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001353 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001354 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001355 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001356 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001357 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001358 //
1359 // Extract the match conditions common for all Flow Entries
1360 //
1361 {
1362 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001363 String matchSrcMac = flowObj.getMatchSrcMac();
1364 if (matchSrcMac != null)
1365 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1366 String matchDstMac = flowObj.getMatchDstMac();
1367 if (matchDstMac != null)
1368 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001369 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1370 if (matchEthernetFrameType != null)
1371 match.enableEthernetFrameType(matchEthernetFrameType);
1372 Short matchVlanId = flowObj.getMatchVlanId();
1373 if (matchVlanId != null)
1374 match.enableVlanId(matchVlanId);
1375 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1376 if (matchVlanPriority != null)
1377 match.enableVlanPriority(matchVlanPriority);
1378 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1379 if (matchSrcIPv4Net != null)
1380 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1381 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1382 if (matchDstIPv4Net != null)
1383 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1384 Byte matchIpProto = flowObj.getMatchIpProto();
1385 if (matchIpProto != null)
1386 match.enableIpProto(matchIpProto);
1387 Byte matchIpToS = flowObj.getMatchIpToS();
1388 if (matchIpToS != null)
1389 match.enableIpToS(matchIpToS);
1390 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1391 if (matchSrcTcpUdpPort != null)
1392 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1393 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1394 if (matchDstTcpUdpPort != null)
1395 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1396
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001397 flowPath.setFlowEntryMatch(match);
1398 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001399 //
1400 // Extract the actions for the first Flow Entry
1401 //
1402 {
1403 String actionsStr = flowObj.getActions();
1404 if (actionsStr != null) {
1405 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1406 flowPath.setFlowEntryActions(flowEntryActions);
1407 }
1408 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001409
1410 //
1411 // Extract all Flow Entries
1412 //
1413 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1414 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001415 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1416 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001417 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001418 flowPath.dataPath().flowEntries().add(flowEntry);
1419 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001420
1421 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001422 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001423
1424 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001425 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1426 *
1427 * @param flowEntryObj the object to extract the Flow Entry State from.
1428 * @return the extracted Flow Entry State.
1429 */
1430 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1431 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1432 String switchDpidStr = flowEntryObj.getSwitchDpid();
1433 String userState = flowEntryObj.getUserState();
1434 String switchState = flowEntryObj.getSwitchState();
1435
1436 if ((flowEntryIdStr == null) ||
1437 (switchDpidStr == null) ||
1438 (userState == null) ||
1439 (switchState == null)) {
1440 // TODO: A work-around, becauuse of some bogus database objects
1441 return null;
1442 }
1443
1444 FlowEntry flowEntry = new FlowEntry();
1445 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1446 flowEntry.setDpid(new Dpid(switchDpidStr));
1447
1448 //
1449 // Extract the match conditions
1450 //
1451 FlowEntryMatch match = new FlowEntryMatch();
1452 Short matchInPort = flowEntryObj.getMatchInPort();
1453 if (matchInPort != null)
1454 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001455 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1456 if (matchSrcMac != null)
1457 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1458 String matchDstMac = flowEntryObj.getMatchDstMac();
1459 if (matchDstMac != null)
1460 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001461 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1462 if (matchEthernetFrameType != null)
1463 match.enableEthernetFrameType(matchEthernetFrameType);
1464 Short matchVlanId = flowEntryObj.getMatchVlanId();
1465 if (matchVlanId != null)
1466 match.enableVlanId(matchVlanId);
1467 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1468 if (matchVlanPriority != null)
1469 match.enableVlanPriority(matchVlanPriority);
1470 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1471 if (matchSrcIPv4Net != null)
1472 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1473 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1474 if (matchDstIPv4Net != null)
1475 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1476 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1477 if (matchIpProto != null)
1478 match.enableIpProto(matchIpProto);
1479 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1480 if (matchIpToS != null)
1481 match.enableIpToS(matchIpToS);
1482 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1483 if (matchSrcTcpUdpPort != null)
1484 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1485 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1486 if (matchDstTcpUdpPort != null)
1487 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001488 flowEntry.setFlowEntryMatch(match);
1489
1490 //
1491 // Extract the actions
1492 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001493 FlowEntryActions actions = new FlowEntryActions();
1494 String actionsStr = flowEntryObj.getActions();
1495 if (actionsStr != null)
1496 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001497 flowEntry.setFlowEntryActions(actions);
1498 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1499 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1500 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001501 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001502 //
1503 return flowEntry;
1504 }
1505
1506 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001507 * Add and maintain a shortest-path flow.
1508 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001509 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001510 *
1511 * @param flowPath the Flow Path with the endpoints and the match
1512 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001513 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001514 */
1515 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001516 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001517 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001518 // Don't do the shortest path computation here.
1519 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001520 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001521
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001522 // We need the DataPath to populate the Network MAP
1523 DataPath dataPath = new DataPath();
1524 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1525 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001526
1527 //
1528 // Prepare the computed Flow Path
1529 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001530 FlowPath computedFlowPath = new FlowPath();
1531 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1532 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001533 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001534 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001535 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001536 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001537
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001538 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001539 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001540 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001541 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001542
1543 // TODO: Mark the flow for maintenance purpose
1544
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001545 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001546 }
1547
1548 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001549 * Reconcile a flow.
1550 *
1551 * @param flowObj the flow that needs to be reconciliated.
1552 * @param newDataPath the new data path to use.
1553 * @return true on success, otherwise false.
1554 */
1555 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
1556 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
1557
1558 //
1559 // Set the incoming port matching and the outgoing port output
1560 // actions for each flow entry.
1561 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001562 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001563 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1564 // Set the incoming port matching
1565 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1566 flowEntry.setFlowEntryMatch(flowEntryMatch);
1567 flowEntryMatch.enableInPort(flowEntry.inPort());
1568
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001569 //
1570 // Set the actions
1571 //
1572 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1573 //
1574 // If the first Flow Entry, copy the Flow Path actions to it
1575 //
1576 if (idx == 0) {
1577 String actionsStr = flowObj.getActions();
1578 if (actionsStr != null) {
1579 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1580 for (FlowEntryAction action : flowActions.actions())
1581 flowEntryActions.addAction(action);
1582 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001583 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001584 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001585 //
1586 // Add the outgoing port output action
1587 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001588 FlowEntryAction flowEntryAction = new FlowEntryAction();
1589 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001590 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001591 }
1592
1593 //
1594 // Remove the old Flow Entries, and add the new Flow Entries
1595 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001596 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1597 LinkedList<IFlowEntry> deleteFlowEntries = new LinkedList<IFlowEntry>();
1598 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001599 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001600 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001601 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001602 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001603 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001604 }
1605
1606 //
1607 // Set the Data Path Summary
1608 //
1609 String dataPathSummaryStr = newDataPath.dataPathSummary();
1610 flowObj.setDataPathSummary(dataPathSummaryStr);
1611
1612 return true;
1613 }
1614
1615 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001616 * Reconcile all flows in a set.
1617 *
1618 * @param flowObjSet the set of flows that need to be reconciliated.
1619 */
1620 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1621 if (! flowObjSet.iterator().hasNext())
1622 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001623 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001624 }
1625
1626 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001627 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001628 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001629 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001630 * @param flowObj the flow path object for the flow entry to install.
1631 * @param flowEntryObj the flow entry object to install.
1632 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001633 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001634 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1635 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001636 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1637 if (flowEntryIdStr == null)
1638 return false;
1639 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001640 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001641 if (userState == null)
1642 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001643
1644 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001645 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001646 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001647 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1648 .getMessage(OFType.FLOW_MOD);
1649 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001650
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001651 short flowModCommand = OFFlowMod.OFPFC_ADD;
1652 if (userState.equals("FE_USER_ADD")) {
1653 flowModCommand = OFFlowMod.OFPFC_ADD;
1654 } else if (userState.equals("FE_USER_MODIFY")) {
1655 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1656 } else if (userState.equals("FE_USER_DELETE")) {
1657 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1658 } else {
1659 // Unknown user state. Ignore the entry
1660 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1661 flowEntryId.toString(), userState);
1662 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001663 }
1664
1665 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001666 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001667 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001668 // NOTE: The Flow matching conditions common for all Flow Entries are
1669 // used ONLY if a Flow Entry does NOT have the corresponding matching
1670 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001671 //
1672 OFMatch match = new OFMatch();
1673 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001674
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001675 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001676 Short matchInPort = flowEntryObj.getMatchInPort();
1677 if (matchInPort != null) {
1678 match.setInputPort(matchInPort);
1679 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1680 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001681
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001682 // Match the Source MAC address
1683 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1684 if (matchSrcMac == null)
1685 matchSrcMac = flowObj.getMatchSrcMac();
1686 if (matchSrcMac != null) {
1687 match.setDataLayerSource(matchSrcMac);
1688 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1689 }
1690
1691 // Match the Destination MAC address
1692 String matchDstMac = flowEntryObj.getMatchDstMac();
1693 if (matchDstMac == null)
1694 matchDstMac = flowObj.getMatchDstMac();
1695 if (matchDstMac != null) {
1696 match.setDataLayerDestination(matchDstMac);
1697 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1698 }
1699
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001700 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001701 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1702 if (matchEthernetFrameType == null)
1703 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1704 if (matchEthernetFrameType != null) {
1705 match.setDataLayerType(matchEthernetFrameType);
1706 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1707 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001708
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001709 // Match the VLAN ID
1710 Short matchVlanId = flowEntryObj.getMatchVlanId();
1711 if (matchVlanId == null)
1712 matchVlanId = flowObj.getMatchVlanId();
1713 if (matchVlanId != null) {
1714 match.setDataLayerVirtualLan(matchVlanId);
1715 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1716 }
1717
1718 // Match the VLAN priority
1719 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1720 if (matchVlanPriority == null)
1721 matchVlanPriority = flowObj.getMatchVlanPriority();
1722 if (matchVlanPriority != null) {
1723 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1724 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1725 }
1726
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001727 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001728 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1729 if (matchSrcIPv4Net == null)
1730 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1731 if (matchSrcIPv4Net != null) {
1732 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1733 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001734
1735 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001736 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1737 if (matchDstIPv4Net == null)
1738 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1739 if (matchDstIPv4Net != null) {
1740 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1741 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001742
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001743 // Match the IP protocol
1744 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1745 if (matchIpProto == null)
1746 matchIpProto = flowObj.getMatchIpProto();
1747 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001748 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001749 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001750 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001751
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001752 // Match the IP ToS (DSCP field, 6 bits)
1753 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1754 if (matchIpToS == null)
1755 matchIpToS = flowObj.getMatchIpToS();
1756 if (matchIpToS != null) {
1757 match.setNetworkTypeOfService(matchIpToS);
1758 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1759 }
1760
1761 // Match the Source TCP/UDP port
1762 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1763 if (matchSrcTcpUdpPort == null)
1764 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1765 if (matchSrcTcpUdpPort != null) {
1766 match.setTransportSource(matchSrcTcpUdpPort);
1767 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1768 }
1769
1770 // Match the Destination TCP/UDP port
1771 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1772 if (matchDstTcpUdpPort == null)
1773 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1774 if (matchDstTcpUdpPort != null) {
1775 match.setTransportDestination(matchDstTcpUdpPort);
1776 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001777 }
1778
1779 //
1780 // Fetch the actions
1781 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001782 Short actionOutputPort = null;
1783 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1784 int actionsLen = 0;
1785 FlowEntryActions flowEntryActions = null;
1786 String actionsStr = flowEntryObj.getActions();
1787 if (actionsStr != null)
1788 flowEntryActions = new FlowEntryActions(actionsStr);
1789 for (FlowEntryAction action : flowEntryActions.actions()) {
1790 ActionOutput actionOutput = action.actionOutput();
1791 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1792 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1793 ActionStripVlan actionStripVlan = action.actionStripVlan();
1794 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1795 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1796 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1797 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1798 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1799 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1800 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1801 ActionEnqueue actionEnqueue = action.actionEnqueue();
1802
1803 if (actionOutput != null) {
1804 actionOutputPort = actionOutput.port().value();
1805 // XXX: The max length is hard-coded for now
1806 OFActionOutput ofa =
1807 new OFActionOutput(actionOutput.port().value(),
1808 (short)0xffff);
1809 openFlowActions.add(ofa);
1810 actionsLen += ofa.getLength();
1811 }
1812
1813 if (actionSetVlanId != null) {
1814 OFActionVirtualLanIdentifier ofa =
1815 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1816 openFlowActions.add(ofa);
1817 actionsLen += ofa.getLength();
1818 }
1819
1820 if (actionSetVlanPriority != null) {
1821 OFActionVirtualLanPriorityCodePoint ofa =
1822 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1823 openFlowActions.add(ofa);
1824 actionsLen += ofa.getLength();
1825 }
1826
1827 if (actionStripVlan != null) {
1828 if (actionStripVlan.stripVlan() == true) {
1829 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1830 openFlowActions.add(ofa);
1831 actionsLen += ofa.getLength();
1832 }
1833 }
1834
1835 if (actionSetEthernetSrcAddr != null) {
1836 OFActionDataLayerSource ofa =
1837 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1838 openFlowActions.add(ofa);
1839 actionsLen += ofa.getLength();
1840 }
1841
1842 if (actionSetEthernetDstAddr != null) {
1843 OFActionDataLayerDestination ofa =
1844 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1845 openFlowActions.add(ofa);
1846 actionsLen += ofa.getLength();
1847 }
1848
1849 if (actionSetIPv4SrcAddr != null) {
1850 OFActionNetworkLayerSource ofa =
1851 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1852 openFlowActions.add(ofa);
1853 actionsLen += ofa.getLength();
1854 }
1855
1856 if (actionSetIPv4DstAddr != null) {
1857 OFActionNetworkLayerDestination ofa =
1858 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1859 openFlowActions.add(ofa);
1860 actionsLen += ofa.getLength();
1861 }
1862
1863 if (actionSetIpToS != null) {
1864 OFActionNetworkTypeOfService ofa =
1865 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1866 openFlowActions.add(ofa);
1867 actionsLen += ofa.getLength();
1868 }
1869
1870 if (actionSetTcpUdpSrcPort != null) {
1871 OFActionTransportLayerSource ofa =
1872 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1873 openFlowActions.add(ofa);
1874 actionsLen += ofa.getLength();
1875 }
1876
1877 if (actionSetTcpUdpDstPort != null) {
1878 OFActionTransportLayerDestination ofa =
1879 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1880 openFlowActions.add(ofa);
1881 actionsLen += ofa.getLength();
1882 }
1883
1884 if (actionEnqueue != null) {
1885 OFActionEnqueue ofa =
1886 new OFActionEnqueue(actionEnqueue.port().value(),
1887 actionEnqueue.queueId());
1888 openFlowActions.add(ofa);
1889 actionsLen += ofa.getLength();
1890 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001891 }
1892
1893 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1894 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1895 .setPriority(PRIORITY_DEFAULT)
1896 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1897 .setCookie(cookie)
1898 .setCommand(flowModCommand)
1899 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001900 .setActions(openFlowActions)
1901 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001902 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1903 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1904 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1905 if (actionOutputPort != null)
1906 fm.setOutPort(actionOutputPort);
1907 }
1908
1909 //
1910 // TODO: Set the following flag
1911 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1912 // See method ForwardingBase::pushRoute()
1913 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001914
1915 //
1916 // Write the message to the switch
1917 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001918 log.debug("MEASUREMENT: Installing flow entry " + userState +
1919 " into switch DPID: " +
1920 mySwitch.getStringId() +
1921 " flowEntryId: " + flowEntryId.toString() +
1922 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1923 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1924 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001925 try {
1926 messageDamper.write(mySwitch, fm, null);
1927 mySwitch.flush();
1928 //
1929 // TODO: We should use the OpenFlow Barrier mechanism
1930 // to check for errors, and update the SwitchState
1931 // for a flow entry after the Barrier message is
1932 // is received.
1933 //
1934 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1935 } catch (IOException e) {
1936 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001937 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001938 }
1939
1940 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001941 }
1942
1943 /**
1944 * Install a Flow Entry on a switch.
1945 *
1946 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001947 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001948 * @param flowEntry the flow entry to install.
1949 * @return true on success, otherwise false.
1950 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001951 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1952 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001953 //
1954 // Create the OpenFlow Flow Modification Entry to push
1955 //
1956 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1957 .getMessage(OFType.FLOW_MOD);
1958 long cookie = flowEntry.flowEntryId().value();
1959
1960 short flowModCommand = OFFlowMod.OFPFC_ADD;
1961 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
1962 flowModCommand = OFFlowMod.OFPFC_ADD;
1963 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
1964 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1965 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
1966 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1967 } else {
1968 // Unknown user state. Ignore the entry
1969 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1970 flowEntry.flowEntryId().toString(),
1971 flowEntry.flowEntryUserState());
1972 return false;
1973 }
1974
1975 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001976 // Fetch the match conditions.
1977 //
1978 // NOTE: The Flow matching conditions common for all Flow Entries are
1979 // used ONLY if a Flow Entry does NOT have the corresponding matching
1980 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001981 //
1982 OFMatch match = new OFMatch();
1983 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001984 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
1985 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
1986
1987 // Match the Incoming Port
1988 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001989 if (matchInPort != null) {
1990 match.setInputPort(matchInPort.value());
1991 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1992 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001993
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001994 // Match the Source MAC address
1995 MACAddress matchSrcMac = flowEntryMatch.srcMac();
1996 if ((matchSrcMac == null) && (flowPathMatch != null)) {
1997 matchSrcMac = flowPathMatch.srcMac();
1998 }
1999 if (matchSrcMac != null) {
2000 match.setDataLayerSource(matchSrcMac.toString());
2001 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2002 }
2003
2004 // Match the Destination MAC address
2005 MACAddress matchDstMac = flowEntryMatch.dstMac();
2006 if ((matchDstMac == null) && (flowPathMatch != null)) {
2007 matchDstMac = flowPathMatch.dstMac();
2008 }
2009 if (matchDstMac != null) {
2010 match.setDataLayerDestination(matchDstMac.toString());
2011 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2012 }
2013
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002014 // Match the Ethernet Frame Type
2015 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2016 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2017 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2018 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002019 if (matchEthernetFrameType != null) {
2020 match.setDataLayerType(matchEthernetFrameType);
2021 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2022 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002023
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002024 // Match the VLAN ID
2025 Short matchVlanId = flowEntryMatch.vlanId();
2026 if ((matchVlanId == null) && (flowPathMatch != null)) {
2027 matchVlanId = flowPathMatch.vlanId();
2028 }
2029 if (matchVlanId != null) {
2030 match.setDataLayerVirtualLan(matchVlanId);
2031 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2032 }
2033
2034 // Match the VLAN priority
2035 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2036 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2037 matchVlanPriority = flowPathMatch.vlanPriority();
2038 }
2039 if (matchVlanPriority != null) {
2040 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2041 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2042 }
2043
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002044 // Match the Source IPv4 Network prefix
2045 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2046 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2047 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2048 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002049 if (matchSrcIPv4Net != null) {
2050 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2051 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002052
2053 // Natch the Destination IPv4 Network prefix
2054 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2055 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2056 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2057 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002058 if (matchDstIPv4Net != null) {
2059 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2060 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002061
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002062 // Match the IP protocol
2063 Byte matchIpProto = flowEntryMatch.ipProto();
2064 if ((matchIpProto == null) && (flowPathMatch != null)) {
2065 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002066 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002067 if (matchIpProto != null) {
2068 match.setNetworkProtocol(matchIpProto);
2069 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002070 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002071
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002072 // Match the IP ToS (DSCP field, 6 bits)
2073 Byte matchIpToS = flowEntryMatch.ipToS();
2074 if ((matchIpToS == null) && (flowPathMatch != null)) {
2075 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002076 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002077 if (matchIpToS != null) {
2078 match.setNetworkTypeOfService(matchIpToS);
2079 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2080 }
2081
2082 // Match the Source TCP/UDP port
2083 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2084 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2085 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2086 }
2087 if (matchSrcTcpUdpPort != null) {
2088 match.setTransportSource(matchSrcTcpUdpPort);
2089 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2090 }
2091
2092 // Match the Destination TCP/UDP port
2093 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2094 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2095 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2096 }
2097 if (matchDstTcpUdpPort != null) {
2098 match.setTransportDestination(matchDstTcpUdpPort);
2099 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002100 }
2101
2102 //
2103 // Fetch the actions
2104 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002105 Short actionOutputPort = null;
2106 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2107 int actionsLen = 0;
2108 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002109 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002110 for (FlowEntryAction action : flowEntryActions.actions()) {
2111 ActionOutput actionOutput = action.actionOutput();
2112 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2113 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2114 ActionStripVlan actionStripVlan = action.actionStripVlan();
2115 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2116 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2117 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2118 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2119 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2120 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2121 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2122 ActionEnqueue actionEnqueue = action.actionEnqueue();
2123
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002124 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002125 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002126 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002127 OFActionOutput ofa =
2128 new OFActionOutput(actionOutput.port().value(),
2129 (short)0xffff);
2130 openFlowActions.add(ofa);
2131 actionsLen += ofa.getLength();
2132 }
2133
2134 if (actionSetVlanId != null) {
2135 OFActionVirtualLanIdentifier ofa =
2136 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2137 openFlowActions.add(ofa);
2138 actionsLen += ofa.getLength();
2139 }
2140
2141 if (actionSetVlanPriority != null) {
2142 OFActionVirtualLanPriorityCodePoint ofa =
2143 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2144 openFlowActions.add(ofa);
2145 actionsLen += ofa.getLength();
2146 }
2147
2148 if (actionStripVlan != null) {
2149 if (actionStripVlan.stripVlan() == true) {
2150 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2151 openFlowActions.add(ofa);
2152 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002153 }
2154 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002155
2156 if (actionSetEthernetSrcAddr != null) {
2157 OFActionDataLayerSource ofa =
2158 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2159 openFlowActions.add(ofa);
2160 actionsLen += ofa.getLength();
2161 }
2162
2163 if (actionSetEthernetDstAddr != null) {
2164 OFActionDataLayerDestination ofa =
2165 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2166 openFlowActions.add(ofa);
2167 actionsLen += ofa.getLength();
2168 }
2169
2170 if (actionSetIPv4SrcAddr != null) {
2171 OFActionNetworkLayerSource ofa =
2172 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2173 openFlowActions.add(ofa);
2174 actionsLen += ofa.getLength();
2175 }
2176
2177 if (actionSetIPv4DstAddr != null) {
2178 OFActionNetworkLayerDestination ofa =
2179 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2180 openFlowActions.add(ofa);
2181 actionsLen += ofa.getLength();
2182 }
2183
2184 if (actionSetIpToS != null) {
2185 OFActionNetworkTypeOfService ofa =
2186 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2187 openFlowActions.add(ofa);
2188 actionsLen += ofa.getLength();
2189 }
2190
2191 if (actionSetTcpUdpSrcPort != null) {
2192 OFActionTransportLayerSource ofa =
2193 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2194 openFlowActions.add(ofa);
2195 actionsLen += ofa.getLength();
2196 }
2197
2198 if (actionSetTcpUdpDstPort != null) {
2199 OFActionTransportLayerDestination ofa =
2200 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2201 openFlowActions.add(ofa);
2202 actionsLen += ofa.getLength();
2203 }
2204
2205 if (actionEnqueue != null) {
2206 OFActionEnqueue ofa =
2207 new OFActionEnqueue(actionEnqueue.port().value(),
2208 actionEnqueue.queueId());
2209 openFlowActions.add(ofa);
2210 actionsLen += ofa.getLength();
2211 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002212 }
2213
2214 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2215 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2216 .setPriority(PRIORITY_DEFAULT)
2217 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2218 .setCookie(cookie)
2219 .setCommand(flowModCommand)
2220 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002221 .setActions(openFlowActions)
2222 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2223 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2224 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2225 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2226 if (actionOutputPort != null)
2227 fm.setOutPort(actionOutputPort);
2228 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002229
2230 //
2231 // TODO: Set the following flag
2232 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2233 // See method ForwardingBase::pushRoute()
2234 //
2235
2236 //
2237 // Write the message to the switch
2238 //
2239 try {
2240 messageDamper.write(mySwitch, fm, null);
2241 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002242 //
2243 // TODO: We should use the OpenFlow Barrier mechanism
2244 // to check for errors, and update the SwitchState
2245 // for a flow entry after the Barrier message is
2246 // is received.
2247 //
2248 // TODO: The FlowEntry Object in Titan should be set
2249 // to FE_SWITCH_UPDATED.
2250 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002251 } catch (IOException e) {
2252 log.error("Failure writing flow mod from network map", e);
2253 return false;
2254 }
2255 return true;
2256 }
2257
2258 /**
2259 * Remove a Flow Entry from a switch.
2260 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002261 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002262 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002263 * @param flowEntry the flow entry to remove.
2264 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002265 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002266 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2267 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002268 //
2269 // The installFlowEntry() method implements both installation
2270 // and removal of flow entries.
2271 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002272 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002273 }
2274
2275 /**
2276 * Install a Flow Entry on a remote controller.
2277 *
2278 * TODO: We need it now: Jono
2279 * - For now it will make a REST call to the remote controller.
2280 * - Internally, it needs to know the name of the remote controller.
2281 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002282 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002283 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002284 * @return true on success, otherwise false.
2285 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002286 public boolean installRemoteFlowEntry(FlowPath flowPath,
2287 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002288 // TODO: We need it now: Jono
2289 // - For now it will make a REST call to the remote controller.
2290 // - Internally, it needs to know the name of the remote controller.
2291 return true;
2292 }
2293
2294 /**
2295 * Remove a flow entry on a remote controller.
2296 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002297 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002298 * @param flowEntry the flow entry to remove.
2299 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002300 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002301 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2302 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002303 //
2304 // The installRemoteFlowEntry() method implements both installation
2305 // and removal of flow entries.
2306 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002307 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002308 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002309}