blob: 2c5f4baa5d0b12a42d6efe5f06fcab3da4165b47 [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;
HIGUCHI Yuta60a10142013-06-14 15:50:10 -070036import net.onrc.onos.ofcontroller.flowmanager.web.FlowWebRoutable;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070037import net.onrc.onos.ofcontroller.topology.ITopologyNetService;
Pavlin Radoslavove1b37bc2013-10-16 03:57:06 -070038import net.onrc.onos.ofcontroller.topology.TopologyManager;
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
admin944ef4f2013-10-08 17:48:37 -070067/**
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -070068 * Flow Manager class for handling the network flows.
admin944ef4f2013-10-08 17:48:37 -070069 */
Pavlin Radoslavov5adf1522013-04-04 17:43:41 -070070public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080071
Toshio Koide9fe1cb22013-06-13 13:51:11 -070072 protected GraphDBOperation op;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080073
74 protected IRestApiService restApi;
Jonathan Hart50a94982013-04-10 14:49:51 -070075 protected volatile IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -070076 protected volatile ITopologyNetService topologyNetService;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070077 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080078
79 protected OFMessageDamper messageDamper;
80
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070081 //
82 // TODO: Values copied from elsewhere (class LearningSwitch).
83 // The local copy should go away!
84 //
85 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
86 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
87 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
88 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
89 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080090
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +000091 // Flow Entry ID generation state
92 private static Random randomGenerator = new Random();
93 private static int nextFlowEntryIdPrefix = 0;
94 private static int nextFlowEntryIdSuffix = 0;
95 private static long nextFlowEntryId = 0;
96
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -070097 // State for measurement purpose
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070098 private static long measurementFlowId = 100000;
99 private static String measurementFlowIdStr = "0x186a0"; // 100000
100 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700101 //
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700102
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800103 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800104 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
105
106 // The periodic task(s)
Jonathan Hart50a94982013-04-10 14:49:51 -0700107 private ScheduledExecutorService mapReaderScheduler;
108 private ScheduledExecutorService shortestPathReconcileScheduler;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700109
admin944ef4f2013-10-08 17:48:37 -0700110 /**
111 * Periodic task for reading the Flow Entries and pushing changes
112 * into the switches.
113 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700114 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800115 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700116 try {
117 runImpl();
118 } catch (Exception e) {
119 log.debug("Exception processing All Flow Entries from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700120 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700121 return;
122 }
123 }
124
125 private void runImpl() {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700126 long startTime = System.nanoTime();
127 int counterAllFlowEntries = 0;
128 int counterMyNotUpdatedFlowEntries = 0;
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700129
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800130 if (floodlightProvider == null) {
131 log.debug("FloodlightProvider service not found!");
132 return;
133 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000134 Map<Long, IOFSwitch> mySwitches =
135 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700136 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700137 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700138 return;
139 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700140 LinkedList<IFlowEntry> addFlowEntries =
141 new LinkedList<IFlowEntry>();
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000142 LinkedList<IFlowEntry> deleteFlowEntries =
143 new LinkedList<IFlowEntry>();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700144
145 //
Pankaj Berdea2e14a92013-04-15 11:59:15 -0700146 // Fetch all Flow Entries which need to be updated and select only my Flow Entries
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700147 // that need to be updated into the switches.
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700148 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700149 boolean processed_measurement_flow = false;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000150 Iterable<IFlowEntry> allFlowEntries =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700151 op.getAllSwitchNotUpdatedFlowEntries();
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700152 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700153 counterAllFlowEntries++;
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000154
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000155 String dpidStr = flowEntryObj.getSwitchDpid();
156 if (dpidStr == null)
157 continue;
158 Dpid dpid = new Dpid(dpidStr);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800159 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000160 if (mySwitch == null)
161 continue; // Ignore the entry: not my switch
162
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700163 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700164 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700165 if (flowObj == null)
166 continue; // Should NOT happen
167 if (flowObj.getFlowId() == null)
168 continue; // Invalid entry
169
170 //
171 // NOTE: For now we process the DELETE before the ADD
172 // to cover the more common scenario.
173 // TODO: This is error prone and needs to be fixed!
174 //
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000175 String userState = flowEntryObj.getUserState();
176 if (userState == null)
177 continue;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700178 if (userState.equals("FE_USER_DELETE")) {
179 // An entry that needs to be deleted.
180 deleteFlowEntries.add(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700181 installFlowEntry(mySwitch, flowObj, flowEntryObj);
182 } else {
183 addFlowEntries.add(flowEntryObj);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700184 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700185 counterMyNotUpdatedFlowEntries++;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700186 // Code for measurement purpose
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700187 // TODO: Commented-out for now
188 /*
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700189 {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700190 if (flowObj.getFlowId().equals(measurementFlowIdStr)) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700191 processed_measurement_flow = true;
192 }
193 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700194 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700195 }
196
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700197 //
198 // Process the Flow Entries that need to be added
199 //
200 for (IFlowEntry flowEntryObj : addFlowEntries) {
201 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700202 op.getFlowPathByFlowEntry(flowEntryObj);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700203 if (flowObj == null)
204 continue; // Should NOT happen
205 if (flowObj.getFlowId() == null)
206 continue; // Invalid entry
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700207
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700208 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700209 IOFSwitch mySwitch = mySwitches.get(dpid.value());
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000210 if (mySwitch == null)
211 continue; // Shouldn't happen
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -0700212 installFlowEntry(mySwitch, flowObj, flowEntryObj);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800213 }
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000214
215 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000216 // Delete all Flow Entries marked for deletion from the
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -0700217 // Network MAP.
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000218 //
219 // TODO: We should use the OpenFlow Barrier mechanism
220 // to check for errors, and delete the Flow Entries after the
221 // Barrier message is received.
222 //
223 while (! deleteFlowEntries.isEmpty()) {
224 IFlowEntry flowEntryObj = deleteFlowEntries.poll();
225 IFlowPath flowObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700226 op.getFlowPathByFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000227 if (flowObj == null) {
228 log.debug("Did not find FlowPath to be deleted");
229 continue;
230 }
231 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700232 op.removeFlowEntry(flowEntryObj);
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000233 }
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700234
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700235 op.commit();
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700236
237 if (processed_measurement_flow) {
238 long estimatedTime =
239 System.nanoTime() - modifiedMeasurementFlowTime;
240 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
241 (double)estimatedTime / 1000000000 + " sec";
242 log.debug(logMsg);
243 }
244
245 long estimatedTime = System.nanoTime() - startTime;
246 double rate = 0.0;
247 if (estimatedTime > 0)
248 rate = ((double)counterAllFlowEntries * 1000000000) / estimatedTime;
249 String logMsg = "MEASUREMENT: Processed AllFlowEntries: " +
250 counterAllFlowEntries + " MyNotUpdatedFlowEntries: " +
251 counterMyNotUpdatedFlowEntries + " in " +
252 (double)estimatedTime / 1000000000 + " sec: " +
253 rate + " paths/s";
254 log.debug(logMsg);
255 }
256 };
257
admin944ef4f2013-10-08 17:48:37 -0700258 /**
259 * Periodic task for reading the Flow Paths and recomputing the
260 * shortest paths.
261 */
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700262 final Runnable shortestPathReconcile = new Runnable() {
263 public void run() {
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700264 try {
265 runImpl();
266 } catch (Exception e) {
267 log.debug("Exception processing All Flows from the Network MAP: ", e);
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700268 op.rollback();
Pavlin Radoslavova75caea2013-04-10 19:11:26 -0700269 return;
270 }
271 }
272
273 private void runImpl() {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700274 long startTime = System.nanoTime();
275 int counterAllFlowPaths = 0;
276 int counterMyFlowPaths = 0;
277
278 if (floodlightProvider == null) {
279 log.debug("FloodlightProvider service not found!");
280 return;
281 }
282 Map<Long, IOFSwitch> mySwitches =
283 floodlightProvider.getSwitches();
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700284 if (mySwitches.isEmpty()) {
Pankaj Berde85a877b2013-10-03 18:26:35 -0700285 log.trace("No switches controlled");
Pankaj Berdebf51e4f2013-10-03 17:49:23 -0700286 return;
287 }
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700288 LinkedList<IFlowPath> deleteFlows = new LinkedList<IFlowPath>();
289
290 boolean processed_measurement_flow = false;
291
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700292 //
293 // Fetch and recompute the Shortest Path for those
294 // Flow Paths this controller is responsible for.
295 //
Pavlin Radoslavov9556b142013-05-20 21:49:04 +0000296 Map<Long, ?> shortestPathTopo =
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700297 topologyNetService.prepareShortestPathTopo();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700298 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700299 for (IFlowPath flowPathObj : allFlowPaths) {
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700300 counterAllFlowPaths++;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700301 if (flowPathObj == null)
302 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700303
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700304 String srcDpidStr = flowPathObj.getSrcSwitch();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000305 if (srcDpidStr == null)
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700306 continue;
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700307 Dpid srcDpid = new Dpid(srcDpidStr);
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700308 //
309 // Use the source DPID as a heuristic to decide
310 // which controller is responsible for maintaining the
311 // shortest path.
312 // NOTE: This heuristic is error-prone: if the switch
313 // goes away and no controller is responsible for that
314 // switch, then the original Flow Path is not cleaned-up
315 //
316 IOFSwitch mySwitch = mySwitches.get(srcDpid.value());
317 if (mySwitch == null)
318 continue; // Ignore: not my responsibility
319
Pavlin Radoslavov99d1b152013-04-09 22:57:33 -0700320 // Test the Data Path Summary string
321 String dataPathSummaryStr = flowPathObj.getDataPathSummary();
322 if (dataPathSummaryStr == null)
323 continue; // Could be invalid entry?
324 if (dataPathSummaryStr.isEmpty())
325 continue; // No need to maintain this flow
326
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000327 //
328 // Test whether we need to complete the Flow cleanup,
329 // if the Flow has been deleted by the user.
330 //
331 String flowUserState = flowPathObj.getUserState();
332 if ((flowUserState != null)
333 && flowUserState.equals("FE_USER_DELETE")) {
334 Iterable<IFlowEntry> flowEntries = flowPathObj.getFlowEntries();
Yuta HIGUCHI2ded2dd2013-10-09 18:06:41 -0700335 final boolean empty = !flowEntries.iterator().hasNext();
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000336 if (empty)
337 deleteFlows.add(flowPathObj);
338 }
339
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000340 // Fetch the fields needed to recompute the shortest path
341 Short srcPortShort = flowPathObj.getSrcPort();
342 String dstDpidStr = flowPathObj.getDstSwitch();
343 Short dstPortShort = flowPathObj.getDstPort();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700344 Long flowPathFlagsLong = flowPathObj.getFlowPathFlags();
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000345 if ((srcPortShort == null) ||
346 (dstDpidStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700347 (dstPortShort == null) ||
348 (flowPathFlagsLong == null)) {
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000349 continue;
350 }
351
352 Port srcPort = new Port(srcPortShort);
353 Dpid dstDpid = new Dpid(dstDpidStr);
354 Port dstPort = new Port(dstPortShort);
355 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
356 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700357 FlowPathFlags flowPathFlags = new FlowPathFlags(flowPathFlagsLong);
Pavlin Radoslavov6db8c6e2013-04-08 00:14:07 +0000358
Pavlin Radoslavov2659a0b2013-04-03 20:30:40 -0700359 counterMyFlowPaths++;
360
Pavlin Radoslavov832aa652013-03-29 16:21:59 -0700361 //
362 // NOTE: Using here the regular getShortestPath() method
363 // won't work here, because that method calls internally
364 // "conn.endTx(Transaction.COMMIT)", and that will
365 // invalidate all handlers to the Titan database.
366 // If we want to experiment with calling here
367 // getShortestPath(), we need to refactor that code
368 // to avoid closing the transaction.
369 //
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700370 DataPath dataPath =
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700371 topologyNetService.getTopoShortestPath(shortestPathTopo,
372 srcSwitchPort,
373 dstSwitchPort);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000374 if (dataPath == null) {
375 // We need the DataPath to compare the paths
376 dataPath = new DataPath();
377 dataPath.setSrcPort(srcSwitchPort);
378 dataPath.setDstPort(dstSwitchPort);
379 }
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700380 dataPath.applyFlowPathFlags(flowPathFlags);
Pavlin Radoslavov4a325822013-04-02 22:16:59 +0000381
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700382 String newDataPathSummaryStr = dataPath.dataPathSummary();
383 if (dataPathSummaryStr.equals(newDataPathSummaryStr))
384 continue; // Nothing changed
385
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700386 reconcileFlow(flowPathObj, dataPath);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700387 }
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000388
389 //
390 // Delete all leftover Flows marked for deletion from the
391 // Network MAP.
392 //
393 while (! deleteFlows.isEmpty()) {
394 IFlowPath flowPathObj = deleteFlows.poll();
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700395 op.removeFlowPath(flowPathObj);
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000396 }
397
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700398 topologyNetService.dropShortestPathTopo(shortestPathTopo);
Pavlin Radoslavov0391b9d2013-03-29 11:54:25 -0700399
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700400 op.commit();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700401
402 if (processed_measurement_flow) {
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700403 long estimatedTime =
404 System.nanoTime() - modifiedMeasurementFlowTime;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700405 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
406 (double)estimatedTime / 1000000000 + " sec";
407 log.debug(logMsg);
408 }
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700409
410 long estimatedTime = System.nanoTime() - startTime;
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700411 double rate = 0.0;
412 if (estimatedTime > 0)
413 rate = ((double)counterAllFlowPaths * 1000000000) / estimatedTime;
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -0700414 String logMsg = "MEASUREMENT: Processed AllFlowPaths: " +
Pavlin Radoslavov1552f952013-04-04 17:51:22 -0700415 counterAllFlowPaths + " MyFlowPaths: " +
416 counterMyFlowPaths + " in " +
417 (double)estimatedTime / 1000000000 + " sec: " +
418 rate + " paths/s";
Pavlin Radoslavov42f02ba2013-04-03 20:07:30 -0700419 log.debug(logMsg);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800420 }
421 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700422
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800423
admin944ef4f2013-10-08 17:48:37 -0700424 /**
425 * Initialize the Flow Manager.
426 *
427 * @param conf the Graph Database configuration string.
428 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800429 @Override
430 public void init(String conf) {
Toshio Koidebfe9b922013-06-18 10:56:05 -0700431 op = new GraphDBOperation(conf);
Pavlin Radoslavov1278ac72013-10-16 04:43:49 -0700432 topologyNetService = new TopologyManager(conf);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800433 }
434
admin944ef4f2013-10-08 17:48:37 -0700435 /**
436 * Shutdown the Flow Manager operation.
437 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800438 public void finalize() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700439 close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800440 }
441
admin944ef4f2013-10-08 17:48:37 -0700442 /**
443 * Shutdown the Flow Manager operation.
444 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800445 @Override
446 public void close() {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700447 op.close();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800448 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800449
admin944ef4f2013-10-08 17:48:37 -0700450 /**
451 * Get the collection of offered module services.
452 *
453 * @return the collection of offered module services.
454 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800455 @Override
456 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
457 Collection<Class<? extends IFloodlightService>> l =
458 new ArrayList<Class<? extends IFloodlightService>>();
459 l.add(IFlowService.class);
460 return l;
461 }
462
admin944ef4f2013-10-08 17:48:37 -0700463 /**
464 * Get the collection of implemented services.
465 *
466 * @return the collection of implemented services.
467 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800468 @Override
469 public Map<Class<? extends IFloodlightService>, IFloodlightService>
470 getServiceImpls() {
471 Map<Class<? extends IFloodlightService>,
472 IFloodlightService> m =
473 new HashMap<Class<? extends IFloodlightService>,
474 IFloodlightService>();
475 m.put(IFlowService.class, this);
476 return m;
477 }
478
admin944ef4f2013-10-08 17:48:37 -0700479 /**
480 * Get the collection of modules this module depends on.
481 *
482 * @return the collection of modules this module depends on.
483 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800484 @Override
485 public Collection<Class<? extends IFloodlightService>>
486 getModuleDependencies() {
487 Collection<Class<? extends IFloodlightService>> l =
488 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800489 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800490 l.add(IRestApiService.class);
491 return l;
492 }
493
admin944ef4f2013-10-08 17:48:37 -0700494 /**
495 * Initialize the module.
496 *
497 * @param context the module context to use for the initialization.
498 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800499 @Override
500 public void init(FloodlightModuleContext context)
501 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700502 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800503 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800504 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800505 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
506 EnumSet.of(OFType.FLOW_MOD),
507 OFMESSAGE_DAMPER_TIMEOUT);
Pavlin Radoslavovddd01ba2013-07-03 15:40:44 -0700508
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800509 // TODO: An ugly hack!
510 String conf = "/tmp/cassandra.titan";
511 this.init(conf);
Jonathan Hart50a94982013-04-10 14:49:51 -0700512
admin944ef4f2013-10-08 17:48:37 -0700513 mapReaderScheduler = Executors.newScheduledThreadPool(1);
514 shortestPathReconcileScheduler = Executors.newScheduledThreadPool(1);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800515 }
516
admin944ef4f2013-10-08 17:48:37 -0700517 /**
518 * Get the next Flow Entry ID to use.
519 *
520 * @return the next Flow Entry ID to use.
521 */
Pavlin Radoslavov4ef543e2013-05-07 13:36:57 -0700522 private synchronized long getNextFlowEntryId() {
Pavlin Radoslavov0b22d0e2013-04-02 01:12:46 +0000523 //
524 // Generate the next Flow Entry ID.
525 // NOTE: For now, the higher 32 bits are random, and
526 // the lower 32 bits are sequential.
527 // In the future, we need a better allocation mechanism.
528 //
529 if ((nextFlowEntryIdSuffix & 0xffffffffL) == 0xffffffffL) {
530 nextFlowEntryIdPrefix = randomGenerator.nextInt();
531 nextFlowEntryIdSuffix = 0;
532 } else {
533 nextFlowEntryIdSuffix++;
534 }
535 long result = (long)nextFlowEntryIdPrefix << 32;
536 result = result | (0xffffffffL & nextFlowEntryIdSuffix);
537 return result;
538 }
539
admin944ef4f2013-10-08 17:48:37 -0700540 /**
541 * Startup module operation.
542 *
543 * @param context the module context to use for the startup.
544 */
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800545 @Override
546 public void startUp(FloodlightModuleContext context) {
admin944ef4f2013-10-08 17:48:37 -0700547 restApi.addRestletRoutable(new FlowWebRoutable());
Jonathan Hart50a94982013-04-10 14:49:51 -0700548
admin944ef4f2013-10-08 17:48:37 -0700549 // Initialize the Flow Entry ID generator
550 nextFlowEntryIdPrefix = randomGenerator.nextInt();
Jonathan Hart50a94982013-04-10 14:49:51 -0700551
admin944ef4f2013-10-08 17:48:37 -0700552 mapReaderScheduler.scheduleAtFixedRate(
553 mapReader, 3, 3, TimeUnit.SECONDS);
554 shortestPathReconcileScheduler.scheduleAtFixedRate(
555 shortestPathReconcile, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800556 }
557
558 /**
559 * Add a flow.
560 *
561 * Internally, ONOS will automatically register the installer for
562 * receiving Flow Path Notifications for that path.
563 *
564 * @param flowPath the Flow Path to install.
565 * @param flowId the return-by-reference Flow ID as assigned internally.
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700566 * @param dataPathSummaryStr the data path summary string if the added
567 * flow will be maintained internally, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800568 * @return true on success, otherwise false.
569 */
570 @Override
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700571 public boolean addFlow(FlowPath flowPath, FlowId flowId,
572 String dataPathSummaryStr) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700573 /*
574 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700575 if (flowPath.flowId().value() == measurementFlowId) {
576 modifiedMeasurementFlowTime = System.nanoTime();
577 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700578 */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800579
580 IFlowPath flowObj = null;
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000581 boolean found = false;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800582 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700583 if ((flowObj = op.searchFlowPath(flowPath.flowId()))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800584 != null) {
585 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
586 flowPath.flowId().toString());
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000587 found = true;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800588 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700589 flowObj = op.newFlowPath();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800590 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
591 flowPath.flowId().toString());
592 }
593 } catch (Exception e) {
594 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700595 op.rollback();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000596
597 StringWriter sw = new StringWriter();
598 e.printStackTrace(new PrintWriter(sw));
599 String stacktrace = sw.toString();
600
601 log.error(":addFlow FlowId:{} failed: {}",
602 flowPath.flowId().toString(),
603 stacktrace);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800604 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700605 if (flowObj == null) {
Masayoshi Kobayashic9da09e2013-03-26 20:52:02 +0000606 log.error(":addFlow FlowId:{} failed: Flow object not created",
607 flowPath.flowId().toString());
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700608 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800609 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700610 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800611
612 //
613 // Set the Flow key:
614 // - flowId
615 //
616 flowObj.setFlowId(flowPath.flowId().toString());
617 flowObj.setType("flow");
618
619 //
620 // Set the Flow attributes:
621 // - flowPath.installerId()
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700622 // - flowPath.flowPathFlags()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800623 // - flowPath.dataPath().srcPort()
624 // - flowPath.dataPath().dstPort()
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700625 // - flowPath.matchSrcMac()
626 // - flowPath.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700627 // - flowPath.matchEthernetFrameType()
628 // - flowPath.matchVlanId()
629 // - flowPath.matchVlanPriority()
630 // - flowPath.matchSrcIPv4Net()
631 // - flowPath.matchDstIPv4Net()
632 // - flowPath.matchIpProto()
633 // - flowPath.matchIpToS()
634 // - flowPath.matchSrcTcpUdpPort()
635 // - flowPath.matchDstTcpUdpPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700636 // - flowPath.flowEntryActions()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800637 //
638 flowObj.setInstallerId(flowPath.installerId().toString());
Pavlin Radoslavov204b2862013-07-12 14:15:36 -0700639 flowObj.setFlowPathFlags(flowPath.flowPathFlags().flags());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800640 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
641 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
642 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
643 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700644 if (flowPath.flowEntryMatch().matchSrcMac()) {
645 flowObj.setMatchSrcMac(flowPath.flowEntryMatch().srcMac().toString());
646 }
647 if (flowPath.flowEntryMatch().matchDstMac()) {
648 flowObj.setMatchDstMac(flowPath.flowEntryMatch().dstMac().toString());
649 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700650 if (flowPath.flowEntryMatch().matchEthernetFrameType()) {
651 flowObj.setMatchEthernetFrameType(flowPath.flowEntryMatch().ethernetFrameType());
652 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700653 if (flowPath.flowEntryMatch().matchVlanId()) {
654 flowObj.setMatchVlanId(flowPath.flowEntryMatch().vlanId());
655 }
656 if (flowPath.flowEntryMatch().matchVlanPriority()) {
657 flowObj.setMatchVlanPriority(flowPath.flowEntryMatch().vlanPriority());
658 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700659 if (flowPath.flowEntryMatch().matchSrcIPv4Net()) {
660 flowObj.setMatchSrcIPv4Net(flowPath.flowEntryMatch().srcIPv4Net().toString());
661 }
662 if (flowPath.flowEntryMatch().matchDstIPv4Net()) {
663 flowObj.setMatchDstIPv4Net(flowPath.flowEntryMatch().dstIPv4Net().toString());
664 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700665 if (flowPath.flowEntryMatch().matchIpProto()) {
666 flowObj.setMatchIpProto(flowPath.flowEntryMatch().ipProto());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700667 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700668 if (flowPath.flowEntryMatch().matchIpToS()) {
669 flowObj.setMatchIpToS(flowPath.flowEntryMatch().ipToS());
670 }
671 if (flowPath.flowEntryMatch().matchSrcTcpUdpPort()) {
672 flowObj.setMatchSrcTcpUdpPort(flowPath.flowEntryMatch().srcTcpUdpPort());
673 }
674 if (flowPath.flowEntryMatch().matchDstTcpUdpPort()) {
675 flowObj.setMatchDstTcpUdpPort(flowPath.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -0700676 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700677 if (! flowPath.flowEntryActions().actions().isEmpty()) {
678 flowObj.setActions(flowPath.flowEntryActions().toString());
679 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800680
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -0700681 if (dataPathSummaryStr != null) {
682 flowObj.setDataPathSummary(dataPathSummaryStr);
683 } else {
684 flowObj.setDataPathSummary("");
685 }
686
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000687 if (found)
688 flowObj.setUserState("FE_USER_MODIFY");
689 else
690 flowObj.setUserState("FE_USER_ADD");
691
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800692 // Flow edges:
693 // HeadFE
694
695
696 //
697 // Flow Entries:
698 // flowPath.dataPath().flowEntries()
699 //
700 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700701 if (addFlowEntry(flowObj, flowEntry) == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700702 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800703 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700704 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800705 }
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700706 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800707
708 //
709 // TODO: We need a proper Flow ID allocation mechanism.
710 //
711 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700712
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800713 return true;
714 }
715
716 /**
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700717 * Add a flow entry to the Network MAP.
718 *
719 * @param flowObj the corresponding Flow Path object for the Flow Entry.
720 * @param flowEntry the Flow Entry to install.
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700721 * @return the added Flow Entry object on success, otherwise null.
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700722 */
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700723 private IFlowEntry addFlowEntry(IFlowPath flowObj, FlowEntry flowEntry) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700724 // Flow edges
725 // HeadFE (TODO)
726
727 //
728 // Assign the FlowEntry ID.
729 //
730 if ((flowEntry.flowEntryId() == null) ||
731 (flowEntry.flowEntryId().value() == 0)) {
732 long id = getNextFlowEntryId();
733 flowEntry.setFlowEntryId(new FlowEntryId(id));
734 }
735
736 IFlowEntry flowEntryObj = null;
737 boolean found = false;
738 try {
739 if ((flowEntryObj =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700740 op.searchFlowEntry(flowEntry.flowEntryId())) != null) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700741 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
742 flowEntry.flowEntryId().toString());
743 found = true;
744 } else {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700745 flowEntryObj = op.newFlowEntry();
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700746 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
747 flowEntry.flowEntryId().toString());
748 }
749 } catch (Exception e) {
750 log.error(":addFlow FlowEntryId:{} failed",
751 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700752 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700753 }
754 if (flowEntryObj == null) {
755 log.error(":addFlow FlowEntryId:{} failed: FlowEntry object not created",
756 flowEntry.flowEntryId().toString());
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700757 return null;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700758 }
759
760 //
761 // Set the Flow Entry key:
762 // - flowEntry.flowEntryId()
763 //
764 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
765 flowEntryObj.setType("flow_entry");
766
767 //
768 // Set the Flow Entry Edges and attributes:
769 // - Switch edge
770 // - InPort edge
771 // - OutPort edge
772 //
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700773 // - flowEntry.dpid()
774 // - flowEntry.flowEntryUserState()
775 // - flowEntry.flowEntrySwitchState()
776 // - flowEntry.flowEntryErrorState()
777 // - flowEntry.matchInPort()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700778 // - flowEntry.matchSrcMac()
779 // - flowEntry.matchDstMac()
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700780 // - flowEntry.matchEthernetFrameType()
781 // - flowEntry.matchVlanId()
782 // - flowEntry.matchVlanPriority()
783 // - flowEntry.matchSrcIPv4Net()
784 // - flowEntry.matchDstIPv4Net()
785 // - flowEntry.matchIpProto()
786 // - flowEntry.matchIpToS()
787 // - flowEntry.matchSrcTcpUdpPort()
788 // - flowEntry.matchDstTcpUdpPort()
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700789 // - flowEntry.actionOutputPort()
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700790 // - flowEntry.actions()
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700791 //
admin944ef4f2013-10-08 17:48:37 -0700792 ISwitchObject sw = op.searchSwitch(flowEntry.dpid().toString());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700793 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
794 flowEntryObj.setSwitch(sw);
795 if (flowEntry.flowEntryMatch().matchInPort()) {
796 IPortObject inport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700797 op.searchPort(flowEntry.dpid().toString(),
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700798 flowEntry.flowEntryMatch().inPort().value());
799 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
800 flowEntryObj.setInPort(inport);
801 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700802 if (flowEntry.flowEntryMatch().matchSrcMac()) {
803 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
804 }
805 if (flowEntry.flowEntryMatch().matchDstMac()) {
806 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
807 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700808 if (flowEntry.flowEntryMatch().matchEthernetFrameType()) {
809 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
810 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700811 if (flowEntry.flowEntryMatch().matchVlanId()) {
812 flowEntryObj.setMatchVlanId(flowEntry.flowEntryMatch().vlanId());
813 }
814 if (flowEntry.flowEntryMatch().matchVlanPriority()) {
815 flowEntryObj.setMatchVlanPriority(flowEntry.flowEntryMatch().vlanPriority());
816 }
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700817 if (flowEntry.flowEntryMatch().matchSrcIPv4Net()) {
818 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
819 }
820 if (flowEntry.flowEntryMatch().matchDstIPv4Net()) {
821 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
822 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700823 if (flowEntry.flowEntryMatch().matchIpProto()) {
824 flowEntryObj.setMatchIpProto(flowEntry.flowEntryMatch().ipProto());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700825 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -0700826 if (flowEntry.flowEntryMatch().matchIpToS()) {
827 flowEntryObj.setMatchIpToS(flowEntry.flowEntryMatch().ipToS());
828 }
829 if (flowEntry.flowEntryMatch().matchSrcTcpUdpPort()) {
830 flowEntryObj.setMatchSrcTcpUdpPort(flowEntry.flowEntryMatch().srcTcpUdpPort());
831 }
832 if (flowEntry.flowEntryMatch().matchDstTcpUdpPort()) {
833 flowEntryObj.setMatchDstTcpUdpPort(flowEntry.flowEntryMatch().dstTcpUdpPort());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700834 }
835
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700836 for (FlowEntryAction fa : flowEntry.flowEntryActions().actions()) {
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700837 if (fa.actionOutput() != null) {
838 IPortObject outport =
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700839 op.searchPort(flowEntry.dpid().toString(),
840 fa.actionOutput().port().value());
Pavlin Radoslavovc1bafd12013-07-12 17:00:35 -0700841 flowEntryObj.setActionOutputPort(fa.actionOutput().port().value());
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700842 flowEntryObj.setOutPort(outport);
843 }
844 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -0700845 if (! flowEntry.flowEntryActions().isEmpty()) {
846 flowEntryObj.setActions(flowEntry.flowEntryActions().toString());
847 }
848
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700849 // TODO: Hacks with hard-coded state names!
850 if (found)
851 flowEntryObj.setUserState("FE_USER_MODIFY");
852 else
853 flowEntryObj.setUserState("FE_USER_ADD");
854 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
855 //
856 // TODO: Take care of the FlowEntryErrorState.
857 //
858
859 // Flow Entries edges:
860 // Flow
861 // NextFE (TODO)
862 if (! found) {
863 flowObj.addFlowEntry(flowEntryObj);
864 flowEntryObj.setFlow(flowObj);
865 }
866
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -0700867 return flowEntryObj;
Pavlin Radoslavov9425f702013-04-04 19:55:07 -0700868 }
869
870 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000871 * Delete all previously added flows.
872 *
873 * @return true on success, otherwise false.
874 */
875 @Override
876 public boolean deleteAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000877 final ConcurrentLinkedQueue<FlowId> concurrentAllFlowIds =
878 new ConcurrentLinkedQueue<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000879
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000880 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700881 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000882 for (IFlowPath flowPathObj : allFlowPaths) {
883 if (flowPathObj == null)
884 continue;
885 String flowIdStr = flowPathObj.getFlowId();
886 if (flowIdStr == null)
887 continue;
888 FlowId flowId = new FlowId(flowIdStr);
889 concurrentAllFlowIds.add(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000890 }
891
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000892 // Delete all flows one-by-one
893 for (FlowId flowId : concurrentAllFlowIds)
894 deleteFlow(flowId);
895
896 /*
897 * TODO: A faster mechanism to delete the Flow Paths by using
898 * a number of threads. Commented-out for now.
899 */
900 /*
901 //
902 // Create the threads to delete the Flow Paths
903 //
Yuta HIGUCHI6f0e4392013-10-09 17:43:34 -0700904 List<Thread> threads = new LinkedList<Thread>();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000905 for (int i = 0; i < 10; i++) {
906 Thread thread = new Thread(new Runnable() {
907 @Override
908 public void run() {
909 while (true) {
910 FlowId flowId = concurrentAllFlowIds.poll();
911 if (flowId == null)
912 return;
913 deleteFlow(flowId);
914 }
915 }}, "Delete All Flow Paths");
916 threads.add(thread);
917 }
918
919 // Start processing
920 for (Thread thread : threads) {
921 thread.start();
922 }
923
Pavlin Radoslavovf5d80412013-05-24 05:14:07 +0000924 // Wait for all threads to complete
Pavlin Radoslavov759772f2013-05-20 20:50:00 +0000925 for (Thread thread : threads) {
926 try {
927 thread.join();
928 } catch (InterruptedException e) {
929 log.debug("Exception waiting for a thread to delete a Flow Path: ", e);
930 }
931 }
932 */
933
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +0000934 return true;
935 }
936
937 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800938 * Delete a previously added flow.
939 *
940 * @param flowId the Flow ID of the flow to delete.
941 * @return true on success, otherwise false.
942 */
943 @Override
944 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700945 /*
946 * TODO: Commented-out for now
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700947 if (flowId.value() == measurementFlowId) {
948 modifiedMeasurementFlowTime = System.nanoTime();
949 }
Pavlin Radoslavov7e154fd2013-04-04 11:15:37 -0700950 */
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700951
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800952 IFlowPath flowObj = null;
953 //
954 // We just mark the entries for deletion,
955 // and let the switches remove each individual entry after
956 // it has been removed from the switches.
957 //
958 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700959 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800960 != null) {
961 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
962 flowId.toString());
963 } else {
964 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
965 flowId.toString());
966 }
967 } catch (Exception e) {
968 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700969 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800970 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
971 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700972 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700973 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800974 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700975 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800976
977 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000978 // Find and mark for deletion all Flow Entries,
979 // and the Flow itself.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800980 //
Pavlin Radoslavov710e2a72013-04-08 02:31:05 +0000981 flowObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800982 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
983 boolean empty = true; // TODO: an ugly hack
984 for (IFlowEntry flowEntryObj : flowEntries) {
985 empty = false;
986 // flowObj.removeFlowEntry(flowEntryObj);
987 // conn.utils().removeFlowEntry(conn, flowEntryObj);
988 flowEntryObj.setUserState("FE_USER_DELETE");
989 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
990 }
991 // Remove from the database empty flows
992 if (empty)
Toshio Koide9fe1cb22013-06-13 13:51:11 -0700993 op.removeFlowPath(flowObj);
994 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800995
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800996 return true;
997 }
998
999 /**
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001000 * Clear the state for all previously added flows.
1001 *
1002 * @return true on success, otherwise false.
1003 */
1004 @Override
1005 public boolean clearAllFlows() {
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001006 List<FlowId> allFlowIds = new LinkedList<FlowId>();
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001007
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001008 // Get all Flow IDs
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001009 Iterable<IFlowPath> allFlowPaths = op.getAllFlowPaths();
Pavlin Radoslavov759772f2013-05-20 20:50:00 +00001010 for (IFlowPath flowPathObj : allFlowPaths) {
1011 if (flowPathObj == null)
1012 continue;
1013 String flowIdStr = flowPathObj.getFlowId();
1014 if (flowIdStr == null)
1015 continue;
1016 FlowId flowId = new FlowId(flowIdStr);
1017 allFlowIds.add(flowId);
1018 }
1019
1020 // Clear all flows one-by-one
1021 for (FlowId flowId : allFlowIds) {
1022 clearFlow(flowId);
Pavlin Radoslavovbaea9242013-05-08 00:20:09 +00001023 }
1024
1025 return true;
1026 }
1027
1028 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001029 * Clear the state for a previously added flow.
1030 *
1031 * @param flowId the Flow ID of the flow to clear.
1032 * @return true on success, otherwise false.
1033 */
1034 @Override
1035 public boolean clearFlow(FlowId flowId) {
1036 IFlowPath flowObj = null;
1037 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001038 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001039 != null) {
1040 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
1041 flowId.toString());
1042 } else {
1043 log.debug("Clearing 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 Radoslavov916832f2013-03-14 17:48:41 -07001049 log.error(":clearFlow 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 Radoslavov916832f2013-03-14 17:48:41 -07001053 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001054 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001055
1056 //
1057 // Remove all Flow Entries
1058 //
1059 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1060 for (IFlowEntry flowEntryObj : flowEntries) {
1061 flowObj.removeFlowEntry(flowEntryObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001062 op.removeFlowEntry(flowEntryObj);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001063 }
1064 // Remove the Flow itself
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001065 op.removeFlowPath(flowObj);
1066 op.commit();
Pavlin Radoslavov916832f2013-03-14 17:48:41 -07001067
1068 return true;
1069 }
1070
1071 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001072 * Get a previously added flow.
1073 *
1074 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001075 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001076 */
1077 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001078 public FlowPath getFlow(FlowId flowId) {
1079 IFlowPath flowObj = null;
1080 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001081 if ((flowObj = op.searchFlowPath(flowId))
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001082 != null) {
1083 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
1084 flowId.toString());
1085 } else {
1086 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
1087 flowId.toString());
1088 }
1089 } catch (Exception e) {
1090 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001091 op.rollback();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001092 log.error(":getFlow FlowId:{} failed", flowId.toString());
1093 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001094 if (flowObj == null) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001095 op.commit();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001096 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001097 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001098
1099 //
1100 // Extract the Flow state
1101 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001102 FlowPath flowPath = extractFlowPath(flowObj);
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001103 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001104
1105 return flowPath;
1106 }
1107
1108 /**
1109 * Get all previously added flows by a specific installer for a given
1110 * data path endpoints.
1111 *
1112 * @param installerId the Caller ID of the installer of the flow to get.
1113 * @param dataPathEndpoints the data path endpoints of the flow to get.
1114 * @return the Flow Paths if found, otherwise null.
1115 */
1116 @Override
1117 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
1118 DataPathEndpoints dataPathEndpoints) {
1119 //
1120 // TODO: The implementation below is not optimal:
1121 // We fetch all flows, and then return only the subset that match
1122 // the query conditions.
1123 // We should use the appropriate Titan/Gremlin query to filter-out
1124 // the flows as appropriate.
1125 //
1126 ArrayList<FlowPath> allFlows = getAllFlows();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001127 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001128
1129 if (allFlows == null) {
1130 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001131 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001132 }
1133
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001134 for (FlowPath flow : allFlows) {
1135 //
1136 // TODO: String-based comparison is sub-optimal.
1137 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001138 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001139 //
1140 if (! flow.installerId().toString().equals(installerId.toString()))
1141 continue;
1142 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1143 continue;
1144 }
1145 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1146 continue;
1147 }
1148 flowPaths.add(flow);
1149 }
1150
1151 if (flowPaths.isEmpty()) {
1152 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001153 } else {
1154 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
1155 }
1156
1157 return flowPaths;
1158 }
1159
1160 /**
1161 * Get all installed flows by all installers for given data path endpoints.
1162 *
1163 * @param dataPathEndpoints the data path endpoints of the flows to get.
1164 * @return the Flow Paths if found, otherwise null.
1165 */
1166 @Override
1167 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
1168 //
1169 // TODO: The implementation below is not optimal:
1170 // We fetch all flows, and then return only the subset that match
1171 // the query conditions.
1172 // We should use the appropriate Titan/Gremlin query to filter-out
1173 // the flows as appropriate.
1174 //
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001175 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
1176 ArrayList<FlowPath> allFlows = getAllFlows();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001177
1178 if (allFlows == null) {
1179 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001180 return flowPaths;
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001181 }
1182
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001183 for (FlowPath flow : allFlows) {
1184 //
1185 // TODO: String-based comparison is sub-optimal.
1186 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -08001187 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001188 //
1189 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
1190 continue;
1191 }
1192 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
1193 continue;
1194 }
1195 flowPaths.add(flow);
1196 }
1197
1198 if (flowPaths.isEmpty()) {
1199 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001200 } else {
1201 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
1202 }
1203
1204 return flowPaths;
1205 }
1206
1207 /**
admin944ef4f2013-10-08 17:48:37 -07001208 * Get summary of all installed flows by all installers in a given range.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001209 *
admin944ef4f2013-10-08 17:48:37 -07001210 * @param flowId the Flow ID of the first flow in the flow range to get.
HIGUCHI Yutaeb567aa2013-10-08 19:27:35 -07001211 * @param maxFlows the maximum number of flows to be returned.
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001212 * @return the Flow Paths if found, otherwise null.
1213 */
1214 @Override
Jonathan Hart01f2d272013-04-04 20:03:46 -07001215 public ArrayList<IFlowPath> getAllFlowsSummary(FlowId flowId, int maxFlows) {
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001216
admin944ef4f2013-10-08 17:48:37 -07001217 //
1218 // TODO: The implementation below is not optimal:
1219 // We fetch all flows, and then return only the subset that match
1220 // the query conditions.
1221 // We should use the appropriate Titan/Gremlin query to filter-out
1222 // the flows as appropriate.
1223 //
Jonathan Hart01f2d272013-04-04 20:03:46 -07001224 //ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001225
Jonathan Hart01f2d272013-04-04 20:03:46 -07001226 ArrayList<IFlowPath> flowPathsWithoutFlowEntries = getAllFlowsWithoutFlowEntries();
1227
Jonathan Hartf5315fb2013-04-05 11:41:56 -07001228 Collections.sort(flowPathsWithoutFlowEntries,
1229 new Comparator<IFlowPath>(){
1230 @Override
1231 public int compare(IFlowPath first, IFlowPath second) {
1232 // TODO Auto-generated method stub
1233 long result = new FlowId(first.getFlowId()).value()
1234 - new FlowId(second.getFlowId()).value();
1235 if (result > 0) return 1;
1236 else if (result < 0) return -1;
1237 else return 0;
1238 }
1239 }
1240 );
1241
Jonathan Hart01f2d272013-04-04 20:03:46 -07001242 return flowPathsWithoutFlowEntries;
1243
1244 /*
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001245 ArrayList<FlowPath> allFlows = getAllFlows();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001246
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001247 if (allFlows == null) {
1248 log.debug("Get FlowPathsSummary for {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001249 return flowPaths;
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001250 }
1251
Umesh Krishnaswamy244b4ae2013-03-29 12:05:15 -07001252 Collections.sort(allFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001253
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001254 for (FlowPath flow : allFlows) {
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001255 flow.setFlowEntryMatch(null);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001256
Pavlin Radoslavov96b43422013-04-04 19:14:56 -07001257 // start from desired flowId
1258 if (flow.flowId().value() < flowId.value()) {
1259 continue;
1260 }
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001261
1262 // Summarize by making null flow entry fields that are not relevant to report
1263 for (FlowEntry flowEntry : flow.dataPath().flowEntries()) {
1264 flowEntry.setFlowEntryActions(null);
1265 flowEntry.setFlowEntryMatch(null);
1266 }
1267
1268 flowPaths.add(flow);
1269 if (maxFlows != 0 && flowPaths.size() >= maxFlows) {
1270 break;
1271 }
1272 }
1273
1274 if (flowPaths.isEmpty()) {
1275 log.debug("Get FlowPathsSummary {} {}: no FlowPaths found", flowId, maxFlows);
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001276 } else {
1277 log.debug("Get FlowPathsSummary for {} {}: FlowPaths were found", flowId, maxFlows);
1278 }
1279
1280 return flowPaths;
Jonathan Hart01f2d272013-04-04 20:03:46 -07001281 */
Umesh Krishnaswamy57a32a92013-03-21 14:21:15 -07001282 }
1283
1284 /**
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001285 * Get all installed flows by all installers.
1286 *
1287 * @return the Flow Paths if found, otherwise null.
1288 */
1289 @Override
1290 public ArrayList<FlowPath> getAllFlows() {
1291 Iterable<IFlowPath> flowPathsObj = null;
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001292 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001293
1294 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001295 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001296 log.debug("Get all FlowPaths: found FlowPaths");
1297 } else {
1298 log.debug("Get all FlowPaths: no FlowPaths found");
1299 }
1300 } catch (Exception e) {
1301 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001302 op.rollback();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001303 log.error(":getAllFlowPaths failed");
1304 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001305 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001306 op.commit();
Umesh Krishnaswamyea0f4ab2013-03-26 18:49:35 -07001307 return flowPaths; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -07001308 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001309
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001310 for (IFlowPath flowObj : flowPathsObj) {
1311 //
1312 // Extract the Flow state
1313 //
1314 FlowPath flowPath = extractFlowPath(flowObj);
Pavlin Radoslavov3f2af732013-03-29 15:29:35 -07001315 if (flowPath != null)
1316 flowPaths.add(flowPath);
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001317 }
1318
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001319 op.commit();
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001320
1321 return flowPaths;
1322 }
admin944ef4f2013-10-08 17:48:37 -07001323
1324 /**
1325 * Get all Flows information, without the associated Flow Entries.
1326 *
1327 * @return all Flows information, without the associated Flow Entries.
1328 */
1329 public ArrayList<IFlowPath> getAllFlowsWithoutFlowEntries() {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001330 Iterable<IFlowPath> flowPathsObj = null;
1331 ArrayList<IFlowPath> flowPathsObjArray = new ArrayList<IFlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001332
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001333 op.commit();
Jonathan Harte6e91872013-04-13 11:10:32 -07001334
Jonathan Hart01f2d272013-04-04 20:03:46 -07001335 try {
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001336 if ((flowPathsObj = op.getAllFlowPaths()) != null) {
Jonathan Hart01f2d272013-04-04 20:03:46 -07001337 log.debug("Get all FlowPaths: found FlowPaths");
1338 } else {
1339 log.debug("Get all FlowPaths: no FlowPaths found");
1340 }
1341 } catch (Exception e) {
1342 // TODO: handle exceptions
Toshio Koide9fe1cb22013-06-13 13:51:11 -07001343 op.rollback();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001344 log.error(":getAllFlowPaths failed");
1345 }
1346 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
1347 return new ArrayList<IFlowPath>(); // No Flows found
1348 }
1349
1350 for (IFlowPath flowObj : flowPathsObj){
1351 flowPathsObjArray.add(flowObj);
1352 }
1353 /*
Yuta HIGUCHI1e3eba82013-10-09 17:34:54 -07001354 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
Jonathan Hart01f2d272013-04-04 20:03:46 -07001355 for (IFlowPath flowObj : flowPathsObj) {
1356 //
1357 // Extract the Flow state
1358 //
1359 FlowPath flowPath = extractFlowPath(flowObj);
1360 if (flowPath != null)
1361 flowPaths.add(flowPath);
1362 }
1363 */
1364
1365 //conn.endTx(Transaction.COMMIT);
1366
1367 return flowPathsObjArray;
1368 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001369
1370 /**
1371 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
1372 *
1373 * @param flowObj the object to extract the Flow Path State from.
1374 * @return the extracted Flow Path State.
1375 */
1376 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavov706df052013-03-06 10:49:07 -08001377 //
1378 // Extract the Flow state
1379 //
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001380 String flowIdStr = flowObj.getFlowId();
1381 String installerIdStr = flowObj.getInstallerId();
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001382 Long flowPathFlags = flowObj.getFlowPathFlags();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001383 String srcSwitchStr = flowObj.getSrcSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001384 Short srcPortShort = flowObj.getSrcPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001385 String dstSwitchStr = flowObj.getDstSwitch();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001386 Short dstPortShort = flowObj.getDstPort();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001387
1388 if ((flowIdStr == null) ||
1389 (installerIdStr == null) ||
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001390 (flowPathFlags == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001391 (srcSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001392 (srcPortShort == null) ||
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001393 (dstSwitchStr == null) ||
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001394 (dstPortShort == null)) {
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001395 // TODO: A work-around, becauuse of some bogus database objects
1396 return null;
1397 }
1398
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001399 FlowPath flowPath = new FlowPath();
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001400 flowPath.setFlowId(new FlowId(flowIdStr));
1401 flowPath.setInstallerId(new CallerId(installerIdStr));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001402 flowPath.setFlowPathFlags(new FlowPathFlags(flowPathFlags));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001403 flowPath.dataPath().srcPort().setDpid(new Dpid(srcSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001404 flowPath.dataPath().srcPort().setPort(new Port(srcPortShort));
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001405 flowPath.dataPath().dstPort().setDpid(new Dpid(dstSwitchStr));
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001406 flowPath.dataPath().dstPort().setPort(new Port(dstPortShort));
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001407 //
1408 // Extract the match conditions common for all Flow Entries
1409 //
1410 {
1411 FlowEntryMatch match = new FlowEntryMatch();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001412 String matchSrcMac = flowObj.getMatchSrcMac();
1413 if (matchSrcMac != null)
1414 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1415 String matchDstMac = flowObj.getMatchDstMac();
1416 if (matchDstMac != null)
1417 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001418 Short matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1419 if (matchEthernetFrameType != null)
1420 match.enableEthernetFrameType(matchEthernetFrameType);
1421 Short matchVlanId = flowObj.getMatchVlanId();
1422 if (matchVlanId != null)
1423 match.enableVlanId(matchVlanId);
1424 Byte matchVlanPriority = flowObj.getMatchVlanPriority();
1425 if (matchVlanPriority != null)
1426 match.enableVlanPriority(matchVlanPriority);
1427 String matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1428 if (matchSrcIPv4Net != null)
1429 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1430 String matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1431 if (matchDstIPv4Net != null)
1432 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1433 Byte matchIpProto = flowObj.getMatchIpProto();
1434 if (matchIpProto != null)
1435 match.enableIpProto(matchIpProto);
1436 Byte matchIpToS = flowObj.getMatchIpToS();
1437 if (matchIpToS != null)
1438 match.enableIpToS(matchIpToS);
1439 Short matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1440 if (matchSrcTcpUdpPort != null)
1441 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1442 Short matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1443 if (matchDstTcpUdpPort != null)
1444 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
1445
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001446 flowPath.setFlowEntryMatch(match);
1447 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001448 //
1449 // Extract the actions for the first Flow Entry
1450 //
1451 {
1452 String actionsStr = flowObj.getActions();
1453 if (actionsStr != null) {
1454 FlowEntryActions flowEntryActions = new FlowEntryActions(actionsStr);
1455 flowPath.setFlowEntryActions(flowEntryActions);
1456 }
1457 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001458
1459 //
1460 // Extract all Flow Entries
1461 //
1462 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
1463 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001464 FlowEntry flowEntry = extractFlowEntry(flowEntryObj);
1465 if (flowEntry == null)
Pavlin Radoslavovc2877682013-03-27 16:40:07 -07001466 continue;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001467 flowPath.dataPath().flowEntries().add(flowEntry);
1468 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08001469
1470 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001471 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001472
1473 /**
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001474 * Extract Flow Entry State from a Titan Database Object @ref IFlowEntry.
1475 *
1476 * @param flowEntryObj the object to extract the Flow Entry State from.
1477 * @return the extracted Flow Entry State.
1478 */
1479 private FlowEntry extractFlowEntry(IFlowEntry flowEntryObj) {
1480 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1481 String switchDpidStr = flowEntryObj.getSwitchDpid();
1482 String userState = flowEntryObj.getUserState();
1483 String switchState = flowEntryObj.getSwitchState();
1484
1485 if ((flowEntryIdStr == null) ||
1486 (switchDpidStr == null) ||
1487 (userState == null) ||
1488 (switchState == null)) {
1489 // TODO: A work-around, becauuse of some bogus database objects
1490 return null;
1491 }
1492
1493 FlowEntry flowEntry = new FlowEntry();
1494 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryIdStr));
1495 flowEntry.setDpid(new Dpid(switchDpidStr));
1496
1497 //
1498 // Extract the match conditions
1499 //
1500 FlowEntryMatch match = new FlowEntryMatch();
1501 Short matchInPort = flowEntryObj.getMatchInPort();
1502 if (matchInPort != null)
1503 match.enableInPort(new Port(matchInPort));
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001504 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1505 if (matchSrcMac != null)
1506 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
1507 String matchDstMac = flowEntryObj.getMatchDstMac();
1508 if (matchDstMac != null)
1509 match.enableDstMac(MACAddress.valueOf(matchDstMac));
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001510 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1511 if (matchEthernetFrameType != null)
1512 match.enableEthernetFrameType(matchEthernetFrameType);
1513 Short matchVlanId = flowEntryObj.getMatchVlanId();
1514 if (matchVlanId != null)
1515 match.enableVlanId(matchVlanId);
1516 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1517 if (matchVlanPriority != null)
1518 match.enableVlanPriority(matchVlanPriority);
1519 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1520 if (matchSrcIPv4Net != null)
1521 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
1522 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1523 if (matchDstIPv4Net != null)
1524 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
1525 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1526 if (matchIpProto != null)
1527 match.enableIpProto(matchIpProto);
1528 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1529 if (matchIpToS != null)
1530 match.enableIpToS(matchIpToS);
1531 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1532 if (matchSrcTcpUdpPort != null)
1533 match.enableSrcTcpUdpPort(matchSrcTcpUdpPort);
1534 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1535 if (matchDstTcpUdpPort != null)
1536 match.enableDstTcpUdpPort(matchDstTcpUdpPort);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001537 flowEntry.setFlowEntryMatch(match);
1538
1539 //
1540 // Extract the actions
1541 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001542 FlowEntryActions actions = new FlowEntryActions();
1543 String actionsStr = flowEntryObj.getActions();
1544 if (actionsStr != null)
1545 actions = new FlowEntryActions(actionsStr);
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001546 flowEntry.setFlowEntryActions(actions);
1547 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
1548 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
1549 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001550 // TODO: Take care of FlowEntryErrorState.
Pavlin Radoslavov99b12752013-04-04 17:28:06 -07001551 //
1552 return flowEntry;
1553 }
1554
1555 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001556 * Add and maintain a shortest-path flow.
1557 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001558 * NOTE: The Flow Path argument does NOT contain flow entries.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001559 *
1560 * @param flowPath the Flow Path with the endpoints and the match
1561 * conditions to install.
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001562 * @return the added shortest-path flow on success, otherwise null.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001563 */
1564 @Override
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001565 public FlowPath addAndMaintainShortestPathFlow(FlowPath flowPath) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001566 //
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001567 // Don't do the shortest path computation here.
1568 // Instead, let the Flow reconciliation thread take care of it.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001569 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001570
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001571 // We need the DataPath to populate the Network MAP
1572 DataPath dataPath = new DataPath();
1573 dataPath.setSrcPort(flowPath.dataPath().srcPort());
1574 dataPath.setDstPort(flowPath.dataPath().dstPort());
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001575
1576 //
1577 // Prepare the computed Flow Path
1578 //
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001579 FlowPath computedFlowPath = new FlowPath();
1580 computedFlowPath.setFlowId(new FlowId(flowPath.flowId().value()));
1581 computedFlowPath.setInstallerId(new CallerId(flowPath.installerId().value()));
Pavlin Radoslavov204b2862013-07-12 14:15:36 -07001582 computedFlowPath.setFlowPathFlags(new FlowPathFlags(flowPath.flowPathFlags().flags()));
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001583 computedFlowPath.setDataPath(dataPath);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001584 computedFlowPath.setFlowEntryMatch(new FlowEntryMatch(flowPath.flowEntryMatch()));
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001585 computedFlowPath.setFlowEntryActions(new FlowEntryActions(flowPath.flowEntryActions()));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001586
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001587 FlowId flowId = new FlowId();
Pavlin Radoslavov8b4b0592013-04-10 04:33:33 +00001588 String dataPathSummaryStr = dataPath.dataPathSummary();
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001589 if (! addFlow(computedFlowPath, flowId, dataPathSummaryStr))
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001590 return null;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001591
1592 // TODO: Mark the flow for maintenance purpose
1593
Pavlin Radoslavove0575292013-03-28 05:35:25 -07001594 return (computedFlowPath);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001595 }
1596
1597 /**
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001598 * Reconcile a flow.
1599 *
1600 * @param flowObj the flow that needs to be reconciliated.
1601 * @param newDataPath the new data path to use.
1602 * @return true on success, otherwise false.
1603 */
1604 public boolean reconcileFlow(IFlowPath flowObj, DataPath newDataPath) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001605
1606 //
1607 // Set the incoming port matching and the outgoing port output
1608 // actions for each flow entry.
1609 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001610 int idx = 0;
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001611 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
1612 // Set the incoming port matching
1613 FlowEntryMatch flowEntryMatch = new FlowEntryMatch();
1614 flowEntry.setFlowEntryMatch(flowEntryMatch);
1615 flowEntryMatch.enableInPort(flowEntry.inPort());
1616
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001617 //
1618 // Set the actions
1619 //
1620 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
1621 //
1622 // If the first Flow Entry, copy the Flow Path actions to it
1623 //
1624 if (idx == 0) {
1625 String actionsStr = flowObj.getActions();
1626 if (actionsStr != null) {
1627 FlowEntryActions flowActions = new FlowEntryActions(actionsStr);
1628 for (FlowEntryAction action : flowActions.actions())
1629 flowEntryActions.addAction(action);
1630 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001631 }
Pavlin Radoslavov282f4ff2013-07-18 11:21:37 -07001632 idx++;
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001633 //
1634 // Add the outgoing port output action
1635 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001636 FlowEntryAction flowEntryAction = new FlowEntryAction();
1637 flowEntryAction.setActionOutput(flowEntry.outPort());
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001638 flowEntryActions.addAction(flowEntryAction);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001639 }
1640
1641 //
1642 // Remove the old Flow Entries, and add the new Flow Entries
1643 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001644 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001645 for (IFlowEntry flowEntryObj : flowEntries) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001646 flowEntryObj.setUserState("FE_USER_DELETE");
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001647 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001648 }
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001649 for (FlowEntry flowEntry : newDataPath.flowEntries()) {
Pavlin Radoslavov6fb76d12013-04-09 22:52:25 -07001650 addFlowEntry(flowObj, flowEntry);
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001651 }
1652
1653 //
1654 // Set the Data Path Summary
1655 //
1656 String dataPathSummaryStr = newDataPath.dataPathSummary();
1657 flowObj.setDataPathSummary(dataPathSummaryStr);
1658
1659 return true;
1660 }
1661
1662 /**
Pavlin Radoslavovdbaaf2e2013-03-29 04:25:55 -07001663 * Reconcile all flows in a set.
1664 *
1665 * @param flowObjSet the set of flows that need to be reconciliated.
1666 */
1667 public void reconcileFlows(Iterable<IFlowPath> flowObjSet) {
1668 if (! flowObjSet.iterator().hasNext())
1669 return;
Pavlin Radoslavov0eeb15d2013-04-05 10:23:51 -07001670 // TODO: Not implemented/used yet.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001671 }
1672
1673 /**
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001674 * Install a Flow Entry on a switch.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001675 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07001676 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001677 * @param flowObj the flow path object for the flow entry to install.
1678 * @param flowEntryObj the flow entry object to install.
1679 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001680 */
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001681 public boolean installFlowEntry(IOFSwitch mySwitch, IFlowPath flowObj,
1682 IFlowEntry flowEntryObj) {
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001683 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
1684 if (flowEntryIdStr == null)
1685 return false;
1686 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001687 String userState = flowEntryObj.getUserState();
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001688 if (userState == null)
1689 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001690
1691 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001692 // Create the Open Flow Flow Modification Entry to push
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001693 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001694 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
1695 .getMessage(OFType.FLOW_MOD);
1696 long cookie = flowEntryId.value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001697
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001698 short flowModCommand = OFFlowMod.OFPFC_ADD;
1699 if (userState.equals("FE_USER_ADD")) {
1700 flowModCommand = OFFlowMod.OFPFC_ADD;
1701 } else if (userState.equals("FE_USER_MODIFY")) {
1702 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
1703 } else if (userState.equals("FE_USER_DELETE")) {
1704 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
1705 } else {
1706 // Unknown user state. Ignore the entry
1707 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
1708 flowEntryId.toString(), userState);
1709 return false;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001710 }
1711
1712 //
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001713 // Fetch the match conditions.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001714 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001715 // NOTE: The Flow matching conditions common for all Flow Entries are
1716 // used ONLY if a Flow Entry does NOT have the corresponding matching
1717 // condition set.
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001718 //
1719 OFMatch match = new OFMatch();
1720 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001721
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001722 // Match the Incoming Port
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001723 Short matchInPort = flowEntryObj.getMatchInPort();
1724 if (matchInPort != null) {
1725 match.setInputPort(matchInPort);
1726 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
1727 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001728
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001729 // Match the Source MAC address
1730 String matchSrcMac = flowEntryObj.getMatchSrcMac();
1731 if (matchSrcMac == null)
1732 matchSrcMac = flowObj.getMatchSrcMac();
1733 if (matchSrcMac != null) {
1734 match.setDataLayerSource(matchSrcMac);
1735 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
1736 }
1737
1738 // Match the Destination MAC address
1739 String matchDstMac = flowEntryObj.getMatchDstMac();
1740 if (matchDstMac == null)
1741 matchDstMac = flowObj.getMatchDstMac();
1742 if (matchDstMac != null) {
1743 match.setDataLayerDestination(matchDstMac);
1744 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
1745 }
1746
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001747 // Match the Ethernet Frame Type
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001748 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
1749 if (matchEthernetFrameType == null)
1750 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
1751 if (matchEthernetFrameType != null) {
1752 match.setDataLayerType(matchEthernetFrameType);
1753 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
1754 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001755
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001756 // Match the VLAN ID
1757 Short matchVlanId = flowEntryObj.getMatchVlanId();
1758 if (matchVlanId == null)
1759 matchVlanId = flowObj.getMatchVlanId();
1760 if (matchVlanId != null) {
1761 match.setDataLayerVirtualLan(matchVlanId);
1762 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
1763 }
1764
1765 // Match the VLAN priority
1766 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
1767 if (matchVlanPriority == null)
1768 matchVlanPriority = flowObj.getMatchVlanPriority();
1769 if (matchVlanPriority != null) {
1770 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
1771 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
1772 }
1773
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001774 // Match the Source IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001775 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
1776 if (matchSrcIPv4Net == null)
1777 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
1778 if (matchSrcIPv4Net != null) {
1779 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
1780 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001781
1782 // Natch the Destination IPv4 Network prefix
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001783 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
1784 if (matchDstIPv4Net == null)
1785 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
1786 if (matchDstIPv4Net != null) {
1787 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
1788 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001789
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001790 // Match the IP protocol
1791 Byte matchIpProto = flowEntryObj.getMatchIpProto();
1792 if (matchIpProto == null)
1793 matchIpProto = flowObj.getMatchIpProto();
1794 if (matchIpProto != null) {
Pavlin Radoslavov3e69d7d2013-07-09 14:49:13 -07001795 match.setNetworkProtocol(matchIpProto);
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001796 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001797 }
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001798
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07001799 // Match the IP ToS (DSCP field, 6 bits)
1800 Byte matchIpToS = flowEntryObj.getMatchIpToS();
1801 if (matchIpToS == null)
1802 matchIpToS = flowObj.getMatchIpToS();
1803 if (matchIpToS != null) {
1804 match.setNetworkTypeOfService(matchIpToS);
1805 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
1806 }
1807
1808 // Match the Source TCP/UDP port
1809 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
1810 if (matchSrcTcpUdpPort == null)
1811 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
1812 if (matchSrcTcpUdpPort != null) {
1813 match.setTransportSource(matchSrcTcpUdpPort);
1814 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
1815 }
1816
1817 // Match the Destination TCP/UDP port
1818 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
1819 if (matchDstTcpUdpPort == null)
1820 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
1821 if (matchDstTcpUdpPort != null) {
1822 match.setTransportDestination(matchDstTcpUdpPort);
1823 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001824 }
1825
1826 //
1827 // Fetch the actions
1828 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001829 Short actionOutputPort = null;
1830 List<OFAction> openFlowActions = new ArrayList<OFAction>();
1831 int actionsLen = 0;
1832 FlowEntryActions flowEntryActions = null;
1833 String actionsStr = flowEntryObj.getActions();
1834 if (actionsStr != null)
1835 flowEntryActions = new FlowEntryActions(actionsStr);
1836 for (FlowEntryAction action : flowEntryActions.actions()) {
1837 ActionOutput actionOutput = action.actionOutput();
1838 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
1839 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
1840 ActionStripVlan actionStripVlan = action.actionStripVlan();
1841 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
1842 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
1843 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
1844 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
1845 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
1846 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
1847 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
1848 ActionEnqueue actionEnqueue = action.actionEnqueue();
1849
1850 if (actionOutput != null) {
1851 actionOutputPort = actionOutput.port().value();
1852 // XXX: The max length is hard-coded for now
1853 OFActionOutput ofa =
1854 new OFActionOutput(actionOutput.port().value(),
1855 (short)0xffff);
1856 openFlowActions.add(ofa);
1857 actionsLen += ofa.getLength();
1858 }
1859
1860 if (actionSetVlanId != null) {
1861 OFActionVirtualLanIdentifier ofa =
1862 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
1863 openFlowActions.add(ofa);
1864 actionsLen += ofa.getLength();
1865 }
1866
1867 if (actionSetVlanPriority != null) {
1868 OFActionVirtualLanPriorityCodePoint ofa =
1869 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
1870 openFlowActions.add(ofa);
1871 actionsLen += ofa.getLength();
1872 }
1873
1874 if (actionStripVlan != null) {
1875 if (actionStripVlan.stripVlan() == true) {
1876 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
1877 openFlowActions.add(ofa);
1878 actionsLen += ofa.getLength();
1879 }
1880 }
1881
1882 if (actionSetEthernetSrcAddr != null) {
1883 OFActionDataLayerSource ofa =
1884 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
1885 openFlowActions.add(ofa);
1886 actionsLen += ofa.getLength();
1887 }
1888
1889 if (actionSetEthernetDstAddr != null) {
1890 OFActionDataLayerDestination ofa =
1891 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
1892 openFlowActions.add(ofa);
1893 actionsLen += ofa.getLength();
1894 }
1895
1896 if (actionSetIPv4SrcAddr != null) {
1897 OFActionNetworkLayerSource ofa =
1898 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
1899 openFlowActions.add(ofa);
1900 actionsLen += ofa.getLength();
1901 }
1902
1903 if (actionSetIPv4DstAddr != null) {
1904 OFActionNetworkLayerDestination ofa =
1905 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
1906 openFlowActions.add(ofa);
1907 actionsLen += ofa.getLength();
1908 }
1909
1910 if (actionSetIpToS != null) {
1911 OFActionNetworkTypeOfService ofa =
1912 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
1913 openFlowActions.add(ofa);
1914 actionsLen += ofa.getLength();
1915 }
1916
1917 if (actionSetTcpUdpSrcPort != null) {
1918 OFActionTransportLayerSource ofa =
1919 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
1920 openFlowActions.add(ofa);
1921 actionsLen += ofa.getLength();
1922 }
1923
1924 if (actionSetTcpUdpDstPort != null) {
1925 OFActionTransportLayerDestination ofa =
1926 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
1927 openFlowActions.add(ofa);
1928 actionsLen += ofa.getLength();
1929 }
1930
1931 if (actionEnqueue != null) {
1932 OFActionEnqueue ofa =
1933 new OFActionEnqueue(actionEnqueue.port().value(),
1934 actionEnqueue.queueId());
1935 openFlowActions.add(ofa);
1936 actionsLen += ofa.getLength();
1937 }
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001938 }
1939
1940 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
1941 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
1942 .setPriority(PRIORITY_DEFAULT)
1943 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
1944 .setCookie(cookie)
1945 .setCommand(flowModCommand)
1946 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07001947 .setActions(openFlowActions)
1948 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001949 fm.setOutPort(OFPort.OFPP_NONE.getValue());
1950 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
1951 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
1952 if (actionOutputPort != null)
1953 fm.setOutPort(actionOutputPort);
1954 }
1955
1956 //
1957 // TODO: Set the following flag
1958 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
1959 // See method ForwardingBase::pushRoute()
1960 //
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001961
1962 //
1963 // Write the message to the switch
1964 //
Pavlin Radoslavov20d35a22013-04-05 10:16:15 -07001965 log.debug("MEASUREMENT: Installing flow entry " + userState +
1966 " into switch DPID: " +
1967 mySwitch.getStringId() +
1968 " flowEntryId: " + flowEntryId.toString() +
1969 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
1970 " inPort: " + matchInPort + " outPort: " + actionOutputPort
1971 );
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001972 try {
1973 messageDamper.write(mySwitch, fm, null);
1974 mySwitch.flush();
1975 //
1976 // TODO: We should use the OpenFlow Barrier mechanism
1977 // to check for errors, and update the SwitchState
1978 // for a flow entry after the Barrier message is
1979 // is received.
1980 //
1981 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
1982 } catch (IOException e) {
1983 log.error("Failure writing flow mod from network map", e);
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07001984 return false;
Pavlin Radoslavovec8e2e62013-04-04 18:18:29 -07001985 }
1986
1987 return true;
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001988 }
1989
1990 /**
1991 * Install a Flow Entry on a switch.
1992 *
1993 * @param mySwitch the switch to install the Flow Entry into.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001994 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07001995 * @param flowEntry the flow entry to install.
1996 * @return true on success, otherwise false.
1997 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07001998 public boolean installFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
1999 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002000 //
2001 // Create the OpenFlow Flow Modification Entry to push
2002 //
2003 OFFlowMod fm = (OFFlowMod) floodlightProvider.getOFMessageFactory()
2004 .getMessage(OFType.FLOW_MOD);
2005 long cookie = flowEntry.flowEntryId().value();
2006
2007 short flowModCommand = OFFlowMod.OFPFC_ADD;
2008 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
2009 flowModCommand = OFFlowMod.OFPFC_ADD;
2010 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
2011 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
2012 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
2013 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
2014 } else {
2015 // Unknown user state. Ignore the entry
2016 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
2017 flowEntry.flowEntryId().toString(),
2018 flowEntry.flowEntryUserState());
2019 return false;
2020 }
2021
2022 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002023 // Fetch the match conditions.
2024 //
2025 // NOTE: The Flow matching conditions common for all Flow Entries are
2026 // used ONLY if a Flow Entry does NOT have the corresponding matching
2027 // condition set.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002028 //
2029 OFMatch match = new OFMatch();
2030 match.setWildcards(OFMatch.OFPFW_ALL);
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002031 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
2032 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
2033
2034 // Match the Incoming Port
2035 Port matchInPort = flowEntryMatch.inPort();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002036 if (matchInPort != null) {
2037 match.setInputPort(matchInPort.value());
2038 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
2039 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002040
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002041 // Match the Source MAC address
2042 MACAddress matchSrcMac = flowEntryMatch.srcMac();
2043 if ((matchSrcMac == null) && (flowPathMatch != null)) {
2044 matchSrcMac = flowPathMatch.srcMac();
2045 }
2046 if (matchSrcMac != null) {
2047 match.setDataLayerSource(matchSrcMac.toString());
2048 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
2049 }
2050
2051 // Match the Destination MAC address
2052 MACAddress matchDstMac = flowEntryMatch.dstMac();
2053 if ((matchDstMac == null) && (flowPathMatch != null)) {
2054 matchDstMac = flowPathMatch.dstMac();
2055 }
2056 if (matchDstMac != null) {
2057 match.setDataLayerDestination(matchDstMac.toString());
2058 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
2059 }
2060
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002061 // Match the Ethernet Frame Type
2062 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
2063 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
2064 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
2065 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002066 if (matchEthernetFrameType != null) {
2067 match.setDataLayerType(matchEthernetFrameType);
2068 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
2069 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002070
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002071 // Match the VLAN ID
2072 Short matchVlanId = flowEntryMatch.vlanId();
2073 if ((matchVlanId == null) && (flowPathMatch != null)) {
2074 matchVlanId = flowPathMatch.vlanId();
2075 }
2076 if (matchVlanId != null) {
2077 match.setDataLayerVirtualLan(matchVlanId);
2078 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
2079 }
2080
2081 // Match the VLAN priority
2082 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
2083 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
2084 matchVlanPriority = flowPathMatch.vlanPriority();
2085 }
2086 if (matchVlanPriority != null) {
2087 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
2088 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
2089 }
2090
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002091 // Match the Source IPv4 Network prefix
2092 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
2093 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
2094 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
2095 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002096 if (matchSrcIPv4Net != null) {
2097 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
2098 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002099
2100 // Natch the Destination IPv4 Network prefix
2101 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
2102 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
2103 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
2104 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002105 if (matchDstIPv4Net != null) {
2106 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
2107 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002108
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002109 // Match the IP protocol
2110 Byte matchIpProto = flowEntryMatch.ipProto();
2111 if ((matchIpProto == null) && (flowPathMatch != null)) {
2112 matchIpProto = flowPathMatch.ipProto();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002113 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002114 if (matchIpProto != null) {
2115 match.setNetworkProtocol(matchIpProto);
2116 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002117 }
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002118
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002119 // Match the IP ToS (DSCP field, 6 bits)
2120 Byte matchIpToS = flowEntryMatch.ipToS();
2121 if ((matchIpToS == null) && (flowPathMatch != null)) {
2122 matchIpToS = flowPathMatch.ipToS();
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002123 }
Pavlin Radoslavovad3a1e62013-07-09 13:30:16 -07002124 if (matchIpToS != null) {
2125 match.setNetworkTypeOfService(matchIpToS);
2126 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
2127 }
2128
2129 // Match the Source TCP/UDP port
2130 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
2131 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
2132 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
2133 }
2134 if (matchSrcTcpUdpPort != null) {
2135 match.setTransportSource(matchSrcTcpUdpPort);
2136 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
2137 }
2138
2139 // Match the Destination TCP/UDP port
2140 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
2141 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
2142 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
2143 }
2144 if (matchDstTcpUdpPort != null) {
2145 match.setTransportDestination(matchDstTcpUdpPort);
2146 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002147 }
2148
2149 //
2150 // Fetch the actions
2151 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002152 Short actionOutputPort = null;
2153 List<OFAction> openFlowActions = new ArrayList<OFAction>();
2154 int actionsLen = 0;
2155 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002156 //
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002157 for (FlowEntryAction action : flowEntryActions.actions()) {
2158 ActionOutput actionOutput = action.actionOutput();
2159 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
2160 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
2161 ActionStripVlan actionStripVlan = action.actionStripVlan();
2162 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
2163 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
2164 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
2165 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
2166 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
2167 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
2168 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
2169 ActionEnqueue actionEnqueue = action.actionEnqueue();
2170
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002171 if (actionOutput != null) {
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002172 actionOutputPort = actionOutput.port().value();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002173 // XXX: The max length is hard-coded for now
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002174 OFActionOutput ofa =
2175 new OFActionOutput(actionOutput.port().value(),
2176 (short)0xffff);
2177 openFlowActions.add(ofa);
2178 actionsLen += ofa.getLength();
2179 }
2180
2181 if (actionSetVlanId != null) {
2182 OFActionVirtualLanIdentifier ofa =
2183 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
2184 openFlowActions.add(ofa);
2185 actionsLen += ofa.getLength();
2186 }
2187
2188 if (actionSetVlanPriority != null) {
2189 OFActionVirtualLanPriorityCodePoint ofa =
2190 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
2191 openFlowActions.add(ofa);
2192 actionsLen += ofa.getLength();
2193 }
2194
2195 if (actionStripVlan != null) {
2196 if (actionStripVlan.stripVlan() == true) {
2197 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
2198 openFlowActions.add(ofa);
2199 actionsLen += ofa.getLength();
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002200 }
2201 }
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002202
2203 if (actionSetEthernetSrcAddr != null) {
2204 OFActionDataLayerSource ofa =
2205 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
2206 openFlowActions.add(ofa);
2207 actionsLen += ofa.getLength();
2208 }
2209
2210 if (actionSetEthernetDstAddr != null) {
2211 OFActionDataLayerDestination ofa =
2212 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
2213 openFlowActions.add(ofa);
2214 actionsLen += ofa.getLength();
2215 }
2216
2217 if (actionSetIPv4SrcAddr != null) {
2218 OFActionNetworkLayerSource ofa =
2219 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
2220 openFlowActions.add(ofa);
2221 actionsLen += ofa.getLength();
2222 }
2223
2224 if (actionSetIPv4DstAddr != null) {
2225 OFActionNetworkLayerDestination ofa =
2226 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
2227 openFlowActions.add(ofa);
2228 actionsLen += ofa.getLength();
2229 }
2230
2231 if (actionSetIpToS != null) {
2232 OFActionNetworkTypeOfService ofa =
2233 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
2234 openFlowActions.add(ofa);
2235 actionsLen += ofa.getLength();
2236 }
2237
2238 if (actionSetTcpUdpSrcPort != null) {
2239 OFActionTransportLayerSource ofa =
2240 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
2241 openFlowActions.add(ofa);
2242 actionsLen += ofa.getLength();
2243 }
2244
2245 if (actionSetTcpUdpDstPort != null) {
2246 OFActionTransportLayerDestination ofa =
2247 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
2248 openFlowActions.add(ofa);
2249 actionsLen += ofa.getLength();
2250 }
2251
2252 if (actionEnqueue != null) {
2253 OFActionEnqueue ofa =
2254 new OFActionEnqueue(actionEnqueue.port().value(),
2255 actionEnqueue.queueId());
2256 openFlowActions.add(ofa);
2257 actionsLen += ofa.getLength();
2258 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002259 }
2260
2261 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
2262 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
2263 .setPriority(PRIORITY_DEFAULT)
2264 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
2265 .setCookie(cookie)
2266 .setCommand(flowModCommand)
2267 .setMatch(match)
Pavlin Radoslavov1bc2c472013-07-17 18:11:37 -07002268 .setActions(openFlowActions)
2269 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
2270 fm.setOutPort(OFPort.OFPP_NONE.getValue());
2271 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
2272 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
2273 if (actionOutputPort != null)
2274 fm.setOutPort(actionOutputPort);
2275 }
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002276
2277 //
2278 // TODO: Set the following flag
2279 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
2280 // See method ForwardingBase::pushRoute()
2281 //
2282
2283 //
2284 // Write the message to the switch
2285 //
2286 try {
2287 messageDamper.write(mySwitch, fm, null);
2288 mySwitch.flush();
Pavlin Radoslavov44a3dcd2013-04-04 18:42:56 -07002289 //
2290 // TODO: We should use the OpenFlow Barrier mechanism
2291 // to check for errors, and update the SwitchState
2292 // for a flow entry after the Barrier message is
2293 // is received.
2294 //
2295 // TODO: The FlowEntry Object in Titan should be set
2296 // to FE_SWITCH_UPDATED.
2297 //
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002298 } catch (IOException e) {
2299 log.error("Failure writing flow mod from network map", e);
2300 return false;
2301 }
2302 return true;
2303 }
2304
2305 /**
2306 * Remove a Flow Entry from a switch.
2307 *
Pavlin Radoslavov2b858f82013-03-28 11:37:37 -07002308 * @param mySwitch the switch to remove the Flow Entry from.
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002309 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002310 * @param flowEntry the flow entry to remove.
2311 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002312 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002313 public boolean removeFlowEntry(IOFSwitch mySwitch, FlowPath flowPath,
2314 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002315 //
2316 // The installFlowEntry() method implements both installation
2317 // and removal of flow entries.
2318 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002319 return (installFlowEntry(mySwitch, flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002320 }
2321
2322 /**
2323 * Install a Flow Entry on a remote controller.
2324 *
2325 * TODO: We need it now: Jono
2326 * - For now it will make a REST call to the remote controller.
2327 * - Internally, it needs to know the name of the remote controller.
2328 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002329 * @param flowPath the flow path for the flow entry to install.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002330 * @param flowEntry the flow entry to install.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002331 * @return true on success, otherwise false.
2332 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002333 public boolean installRemoteFlowEntry(FlowPath flowPath,
2334 FlowEntry flowEntry) {
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002335 // TODO: We need it now: Jono
2336 // - For now it will make a REST call to the remote controller.
2337 // - Internally, it needs to know the name of the remote controller.
2338 return true;
2339 }
2340
2341 /**
2342 * Remove a flow entry on a remote controller.
2343 *
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002344 * @param flowPath the flow path for the flow entry to remove.
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002345 * @param flowEntry the flow entry to remove.
2346 * @return true on success, otherwise false.
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002347 */
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002348 public boolean removeRemoteFlowEntry(FlowPath flowPath,
2349 FlowEntry flowEntry) {
Pavlin Radoslavov6b6f4a82013-03-28 03:30:00 -07002350 //
2351 // The installRemoteFlowEntry() method implements both installation
2352 // and removal of flow entries.
2353 //
Pavlin Radoslavov67b3ef32013-04-03 02:44:48 -07002354 return (installRemoteFlowEntry(flowPath, flowEntry));
Pavlin Radoslavovb9fe6b42013-03-27 16:25:05 -07002355 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08002356}