blob: a00d5d9d2969c1fead0316c7a636459904116cbb [file] [log] [blame]
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08001package net.floodlightcontroller.flowcache;
2
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08003import java.io.IOException;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08004import java.util.ArrayList;
5import java.util.Collection;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08006import java.util.EnumSet;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08007import java.util.HashMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -08008import java.util.List;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -08009import java.util.Map;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070010import java.util.TreeMap;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080011import java.util.concurrent.Executors;
12import java.util.concurrent.ScheduledExecutorService;
13import java.util.concurrent.ScheduledFuture;
14import java.util.concurrent.TimeUnit;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080015
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080016import net.floodlightcontroller.core.IFloodlightProviderService;
17import net.floodlightcontroller.core.INetMapStorage;
18import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowEntry;
19import net.floodlightcontroller.core.INetMapTopologyObjects.IFlowPath;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070020import net.floodlightcontroller.core.INetMapTopologyService.ITopoRouteService;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080021import net.floodlightcontroller.core.IOFSwitch;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080022import net.floodlightcontroller.core.module.FloodlightModuleContext;
23import net.floodlightcontroller.core.module.FloodlightModuleException;
24import net.floodlightcontroller.core.module.IFloodlightModule;
25import net.floodlightcontroller.core.module.IFloodlightService;
26import net.floodlightcontroller.flowcache.IFlowService;
27import net.floodlightcontroller.flowcache.web.FlowWebRoutable;
28import net.floodlightcontroller.restserver.IRestApiService;
29import net.floodlightcontroller.util.CallerId;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080030import net.floodlightcontroller.util.DataPath;
31import net.floodlightcontroller.util.Dpid;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080032import net.floodlightcontroller.util.DataPathEndpoints;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080033import net.floodlightcontroller.util.FlowEntry;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070034import net.floodlightcontroller.util.FlowEntryAction;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080035import net.floodlightcontroller.util.FlowEntryId;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070036import net.floodlightcontroller.util.FlowEntryMatch;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080037import net.floodlightcontroller.util.FlowEntrySwitchState;
38import net.floodlightcontroller.util.FlowEntryUserState;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080039import net.floodlightcontroller.util.FlowId;
40import net.floodlightcontroller.util.FlowPath;
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -070041import net.floodlightcontroller.util.IPv4Net;
42import net.floodlightcontroller.util.MACAddress;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080043import net.floodlightcontroller.util.OFMessageDamper;
44import net.floodlightcontroller.util.Port;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070045import net.floodlightcontroller.util.SwitchPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080046import net.onrc.onos.util.GraphDBConnection;
47import net.onrc.onos.util.GraphDBConnection.Transaction;
48
49import org.openflow.protocol.OFFlowMod;
50import org.openflow.protocol.OFMatch;
51import org.openflow.protocol.OFPacketOut;
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070052import org.openflow.protocol.OFPort;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080053import org.openflow.protocol.OFType;
54import org.openflow.protocol.action.OFAction;
55import org.openflow.protocol.action.OFActionOutput;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080056
57import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080060public class FlowManager implements IFloodlightModule, IFlowService, INetMapStorage {
61
62 public GraphDBConnection conn;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080063
64 protected IRestApiService restApi;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080065 protected IFloodlightProviderService floodlightProvider;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070066 protected FloodlightModuleContext context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080067
68 protected OFMessageDamper messageDamper;
69
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -070070 //
71 // TODO: Values copied from elsewhere (class LearningSwitch).
72 // The local copy should go away!
73 //
74 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
75 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
76 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
77 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
78 public static final short PRIORITY_DEFAULT = 100;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080079
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070080 private static long nextFlowEntryId = 1;
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070081 private static long measurementFlowId = 100000;
82 private static String measurementFlowIdStr = "0x186a0"; // 100000
83 private long modifiedMeasurementFlowTime = 0;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -070084
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -080085 /** The logger. */
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080086 private static Logger log = LoggerFactory.getLogger(FlowManager.class);
87
88 // The periodic task(s)
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070089 private final ScheduledExecutorService measureShortestPathScheduler =
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -080090 Executors.newScheduledThreadPool(1);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -070091 private final ScheduledExecutorService measureMapReaderScheduler =
92 Executors.newScheduledThreadPool(1);
93 private final ScheduledExecutorService mapReaderScheduler =
94 Executors.newScheduledThreadPool(1);
95
96 final Runnable measureShortestPath = new Runnable() {
97 public void run() {
98 log.debug("Recomputing Shortest Paths from the Network Map Flows...");
99 if (floodlightProvider == null) {
100 log.debug("FloodlightProvider service not found!");
101 return;
102 }
103
104 ITopoRouteService topoRouteService =
105 context.getServiceImpl(ITopoRouteService.class);
106 if (topoRouteService == null) {
107 log.debug("Topology Route Service not found");
108 return;
109 }
110
111 //
112 // Recompute the Shortest Paths for all Flows
113 //
114 int counter = 0;
115 long startTime = System.nanoTime();
116 Iterable<IFlowPath> allFlowPaths = conn.utils().getAllFlowPaths(conn);
117 for (IFlowPath flowPathObj : allFlowPaths) {
118 counter++;
119 FlowId flowId = new FlowId(flowPathObj.getFlowId());
120
121 // log.debug("Found Path {}", flowId.toString());
122 Dpid srcDpid = new Dpid(flowPathObj.getSrcSwitch());
123 Port srcPort = new Port(flowPathObj.getSrcPort());
124 Dpid dstDpid = new Dpid(flowPathObj.getDstSwitch());
125 Port dstPort = new Port(flowPathObj.getDstPort());
126 SwitchPort srcSwitchPort = new SwitchPort(srcDpid, srcPort);
127 SwitchPort dstSwitchPort = new SwitchPort(dstDpid, dstPort);
128 DataPath dataPath =
129 topoRouteService.getShortestPath(srcSwitchPort,
130 dstSwitchPort);
131 }
132 conn.endTx(Transaction.COMMIT);
133
134 long estimatedTime = System.nanoTime() - startTime;
135 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
136 String logMsg = "MEASUREMENT: Computed " + counter + " shortest paths in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " flows/s";
137 log.debug(logMsg);
138 }
139 };
140
141 final Runnable measureMapReader = new Runnable() {
142 public void run() {
143 if (floodlightProvider == null) {
144 log.debug("FloodlightProvider service not found!");
145 return;
146 }
147
148 //
149 // Fetch all Flow Entries
150 //
151 int counter = 0;
152 long startTime = System.nanoTime();
153 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
154 for (IFlowEntry flowEntryObj : allFlowEntries) {
155 counter++;
156 FlowEntryId flowEntryId =
157 new FlowEntryId(flowEntryObj.getFlowEntryId());
158 String userState = flowEntryObj.getUserState();
159 String switchState = flowEntryObj.getSwitchState();
160 }
161 conn.endTx(Transaction.COMMIT);
162
163 long estimatedTime = System.nanoTime() - startTime;
164 double rate = (estimatedTime > 0)? ((double)counter * 1000000000) / estimatedTime: 0.0;
165 String logMsg = "MEASUREMENT: Fetched " + counter + " flow entries in " + (double)estimatedTime / 1000000000 + " sec: " + rate + " entries/s";
166 log.debug(logMsg);
167 }
168 };
169
170 final Runnable mapReader = new Runnable() {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800171 public void run() {
172 // log.debug("Reading Flow Entries from the Network Map...");
173 if (floodlightProvider == null) {
174 log.debug("FloodlightProvider service not found!");
175 return;
176 }
177
178 Map<Long, IOFSwitch> mySwitches = floodlightProvider.getSwitches();
179
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700180 Map<Long, IFlowEntry> myFlowEntries = new TreeMap<Long, IFlowEntry>();
181
182 //
183 // Fetch all Flow Entries and select only my Flow Entries
184 //
185 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
186 for (IFlowEntry flowEntryObj : allFlowEntries) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800187 FlowEntryId flowEntryId =
188 new FlowEntryId(flowEntryObj.getFlowEntryId());
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700189 String userState = flowEntryObj.getUserState();
190 String switchState = flowEntryObj.getSwitchState();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800191
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700192 log.debug("Found Flow Entry {}: {}",
193 flowEntryId.toString(),
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700194 "User State: " + userState +
195 " Switch State: " + switchState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800196
197 if (! switchState.equals("FE_SWITCH_NOT_UPDATED")) {
198 // Ignore the entry: nothing to do
199 continue;
200 }
201
202 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
203 IOFSwitch mySwitch = mySwitches.get(dpid.value());
204 if (mySwitch == null) {
Pavlin Radoslavov79a67c12013-03-15 21:05:53 -0700205 log.debug("Flow Entry ignored: not my switch (FlowEntryId = {} DPID = {})", flowEntryId.toString(), dpid.toString());
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800206 continue;
207 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700208 myFlowEntries.put(flowEntryId.value(), flowEntryObj);
209 }
210
211 //
212 // Process my Flow Entries
213 //
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700214 Boolean processed_measurement_flow = false;
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700215 for (Map.Entry<Long, IFlowEntry> entry : myFlowEntries.entrySet()) {
216 IFlowEntry flowEntryObj = entry.getValue();
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700217 // Code for measurement purpose
218 {
219 IFlowPath flowObj =
220 conn.utils().getFlowPathByFlowEntry(conn,
221 flowEntryObj);
222 if ((flowObj != null) &&
223 flowObj.getFlowId().equals(measurementFlowIdStr)) {
224 processed_measurement_flow = true;
225 }
226 }
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700227
228 //
229 // TODO: Eliminate the re-fetching of flowEntryId,
230 // userState, switchState, and dpid from the flowEntryObj.
231 //
232 FlowEntryId flowEntryId =
233 new FlowEntryId(flowEntryObj.getFlowEntryId());
234 Dpid dpid = new Dpid(flowEntryObj.getSwitchDpid());
235 String userState = flowEntryObj.getUserState();
236 String switchState = flowEntryObj.getSwitchState();
237 IOFSwitch mySwitch = mySwitches.get(dpid.value());
238 if (mySwitch == null) {
239 log.debug("Flow Entry ignored: not my switch");
240 continue;
241 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800242
243 //
244 // Create the Open Flow Flow Modification Entry to push
245 //
246 OFFlowMod fm =
247 (OFFlowMod) floodlightProvider.getOFMessageFactory()
248 .getMessage(OFType.FLOW_MOD);
249 long cookie = flowEntryId.value();
250
251 short flowModCommand = OFFlowMod.OFPFC_ADD;
252 if (userState.equals("FE_USER_ADD")) {
253 flowModCommand = OFFlowMod.OFPFC_ADD;
254 } else if (userState.equals("FE_USER_MODIFY")) {
255 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
256 } else if (userState.equals("FE_USER_DELETE")) {
257 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
258 } else {
259 // Unknown user state. Ignore the entry
Pavlin Radoslavov2f9d6332013-03-18 23:05:48 -0700260 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
261 flowEntryId.toString(), userState);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800262 continue;
263 }
264
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700265 //
266 // Fetch the match conditions
267 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800268 OFMatch match = new OFMatch();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700269 match.setWildcards(OFMatch.OFPFW_ALL);
270 Short matchInPort = flowEntryObj.getMatchInPort();
271 if (matchInPort != null) {
272 match.setInputPort(matchInPort);
273 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
274 }
275 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
276 if (matchEthernetFrameType != null) {
277 match.setDataLayerType(matchEthernetFrameType);
278 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
279 }
280 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
281 if (matchSrcIPv4Net != null) {
282 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
283 }
284 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
285 if (matchDstIPv4Net != null) {
286 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
287 }
288 String matchSrcMac = flowEntryObj.getMatchSrcMac();
289 if (matchSrcMac != null) {
290 match.setDataLayerSource(matchSrcMac);
291 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
292 }
293 String matchDstMac = flowEntryObj.getMatchDstMac();
294 if (matchDstMac != null) {
295 match.setDataLayerDestination(matchDstMac);
296 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
297 }
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700298
299 //
300 // Fetch the actions
301 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800302 List<OFAction> actions = new ArrayList<OFAction>();
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700303 Short actionOutputPort = flowEntryObj.getActionOutput();
304 if (actionOutputPort != null) {
305 OFActionOutput action = new OFActionOutput();
306 // XXX: The max length is hard-coded for now
307 action.setMaxLength((short)0xffff);
308 action.setPort(actionOutputPort);
309 actions.add(action);
310 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800311
312 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
313 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700314 .setPriority(PRIORITY_DEFAULT)
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800315 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
316 .setCookie(cookie)
317 .setCommand(flowModCommand)
318 .setMatch(match)
319 .setActions(actions)
320 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
Pavlin Radoslavov78c4e492013-03-12 17:17:48 -0700321 fm.setOutPort(OFPort.OFPP_NONE.getValue());
322 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
323 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
324 if (actionOutputPort != null)
325 fm.setOutPort(actionOutputPort);
326 }
327
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800328 //
329 // TODO: Set the following flag
330 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
331 // See method ForwardingBase::pushRoute()
332 //
333 try {
334 messageDamper.write(mySwitch, fm, null);
335 mySwitch.flush();
336 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
337 if (userState.equals("FE_USER_DELETE")) {
338 // Delete the entry
339 IFlowPath flowObj = null;
340 flowObj = conn.utils().getFlowPathByFlowEntry(conn,
341 flowEntryObj);
342 if (flowObj != null)
343 log.debug("Found FlowPath to be deleted");
344 else
345 log.debug("Did not find FlowPath to be deleted");
346 flowObj.removeFlowEntry(flowEntryObj);
347 conn.utils().removeFlowEntry(conn, flowEntryObj);
348
349 // Test whether the last flow entry
350 Iterable<IFlowEntry> tmpflowEntries =
351 flowObj.getFlowEntries();
352 boolean found = false;
353 for (IFlowEntry tmpflowEntryObj : tmpflowEntries) {
354 found = true;
355 break;
356 }
357 if (! found) {
358 // Remove the Flow Path as well
359 conn.utils().removeFlowPath(conn, flowObj);
360 }
361 }
362 } catch (IOException e) {
363 log.error("Failure writing flow mod from network map", e);
364 }
365 }
366 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700367
368 if (processed_measurement_flow) {
369 long estimatedTime = System.nanoTime() - modifiedMeasurementFlowTime;
370 String logMsg = "MEASUREMENT: Pushed Flow delay: " +
371 (double)estimatedTime / 1000000000 + " sec";
372 log.debug(logMsg);
373 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800374 }
375 };
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700376
377 /*
378 final ScheduledFuture<?> measureShortestPathHandle =
379 measureShortestPathScheduler.scheduleAtFixedRate(measureShortestPath, 10, 10, TimeUnit.SECONDS);
380 */
381
382 /*
383 final ScheduledFuture<?> measureMapReaderHandle =
384 measureMapReaderScheduler.scheduleAtFixedRate(measureMapReader, 10, 10, TimeUnit.SECONDS);
385 */
386
387 final ScheduledFuture<?> mapReaderHandle =
388 mapReaderScheduler.scheduleAtFixedRate(mapReader, 3, 3, TimeUnit.SECONDS);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800389
390 @Override
391 public void init(String conf) {
392 conn = GraphDBConnection.getInstance(conf);
393 }
394
395 public void finalize() {
396 close();
397 }
398
399 @Override
400 public void close() {
401 conn.close();
402 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800403
404 @Override
405 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
406 Collection<Class<? extends IFloodlightService>> l =
407 new ArrayList<Class<? extends IFloodlightService>>();
408 l.add(IFlowService.class);
409 return l;
410 }
411
412 @Override
413 public Map<Class<? extends IFloodlightService>, IFloodlightService>
414 getServiceImpls() {
415 Map<Class<? extends IFloodlightService>,
416 IFloodlightService> m =
417 new HashMap<Class<? extends IFloodlightService>,
418 IFloodlightService>();
419 m.put(IFlowService.class, this);
420 return m;
421 }
422
423 @Override
424 public Collection<Class<? extends IFloodlightService>>
425 getModuleDependencies() {
426 Collection<Class<? extends IFloodlightService>> l =
427 new ArrayList<Class<? extends IFloodlightService>>();
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800428 l.add(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800429 l.add(IRestApiService.class);
430 return l;
431 }
432
433 @Override
434 public void init(FloodlightModuleContext context)
435 throws FloodlightModuleException {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700436 this.context = context;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800437 floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800438 restApi = context.getServiceImpl(IRestApiService.class);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800439 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
440 EnumSet.of(OFType.FLOW_MOD),
441 OFMESSAGE_DAMPER_TIMEOUT);
442 // TODO: An ugly hack!
443 String conf = "/tmp/cassandra.titan";
444 this.init(conf);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800445 }
446
447 @Override
448 public void startUp(FloodlightModuleContext context) {
449 restApi.addRestletRoutable(new FlowWebRoutable());
Pavlin Radoslavov80ca6302013-03-20 02:08:09 -0700450
451 //
452 // Extract all flow entries and assign the next Flow Entry ID
453 // to be larger than the largest Flow Entry ID
454 //
455 Iterable<IFlowEntry> allFlowEntries = conn.utils().getAllFlowEntries(conn);
456 for (IFlowEntry flowEntryObj : allFlowEntries) {
457 FlowEntryId flowEntryId =
458 new FlowEntryId(flowEntryObj.getFlowEntryId());
459 if (flowEntryId.value() >= nextFlowEntryId)
460 nextFlowEntryId = flowEntryId.value() + 1;
461 }
462 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800463 }
464
465 /**
466 * Add a flow.
467 *
468 * Internally, ONOS will automatically register the installer for
469 * receiving Flow Path Notifications for that path.
470 *
471 * @param flowPath the Flow Path to install.
472 * @param flowId the return-by-reference Flow ID as assigned internally.
473 * @return true on success, otherwise false.
474 */
475 @Override
476 public boolean addFlow(FlowPath flowPath, FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700477 if (flowPath.flowId().value() == measurementFlowId) {
478 modifiedMeasurementFlowTime = System.nanoTime();
479 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800480
481 //
482 // Assign the FlowEntry IDs
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700483 // Right now every new flow entry gets a new flow entry ID
484 // TODO: This needs to be redesigned!
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800485 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800486 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
Pavlin Radoslavov01391c92013-03-14 17:13:21 -0700487 long id = nextFlowEntryId++;
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800488 flowEntry.setFlowEntryId(new FlowEntryId(id));
489 }
490
491 IFlowPath flowObj = null;
492 try {
493 if ((flowObj = conn.utils().searchFlowPath(conn, flowPath.flowId()))
494 != null) {
495 log.debug("Adding FlowPath with FlowId {}: found existing FlowPath",
496 flowPath.flowId().toString());
497 } else {
498 flowObj = conn.utils().newFlowPath(conn);
499 log.debug("Adding FlowPath with FlowId {}: creating new FlowPath",
500 flowPath.flowId().toString());
501 }
502 } catch (Exception e) {
503 // TODO: handle exceptions
504 conn.endTx(Transaction.ROLLBACK);
505 log.error(":addFlow FlowId:{} failed",
506 flowPath.flowId().toString());
507 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700508 if (flowObj == null) {
509 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800510 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700511 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800512
513 //
514 // Set the Flow key:
515 // - flowId
516 //
517 flowObj.setFlowId(flowPath.flowId().toString());
518 flowObj.setType("flow");
519
520 //
521 // Set the Flow attributes:
522 // - flowPath.installerId()
523 // - flowPath.dataPath().srcPort()
524 // - flowPath.dataPath().dstPort()
525 //
526 flowObj.setInstallerId(flowPath.installerId().toString());
527 flowObj.setSrcSwitch(flowPath.dataPath().srcPort().dpid().toString());
528 flowObj.setSrcPort(flowPath.dataPath().srcPort().port().value());
529 flowObj.setDstSwitch(flowPath.dataPath().dstPort().dpid().toString());
530 flowObj.setDstPort(flowPath.dataPath().dstPort().port().value());
531
532 // Flow edges:
533 // HeadFE
534
535
536 //
537 // Flow Entries:
538 // flowPath.dataPath().flowEntries()
539 //
540 for (FlowEntry flowEntry : flowPath.dataPath().flowEntries()) {
541 IFlowEntry flowEntryObj = null;
542 boolean found = false;
543 try {
544 if ((flowEntryObj = conn.utils().searchFlowEntry(conn, flowEntry.flowEntryId())) != null) {
545 log.debug("Adding FlowEntry with FlowEntryId {}: found existing FlowEntry",
546 flowEntry.flowEntryId().toString());
547 found = true;
548 } else {
549 flowEntryObj = conn.utils().newFlowEntry(conn);
550 log.debug("Adding FlowEntry with FlowEntryId {}: creating new FlowEntry",
551 flowEntry.flowEntryId().toString());
552 }
553 } catch (Exception e) {
554 // TODO: handle exceptions
555 conn.endTx(Transaction.ROLLBACK);
556 log.error(":addFlow FlowEntryId:{} failed",
557 flowEntry.flowEntryId().toString());
558 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700559 if (flowEntryObj == null) {
560 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800561 return false;
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700562 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800563
564 //
565 // Set the Flow Entry key:
566 // - flowEntry.flowEntryId()
567 //
568 flowEntryObj.setFlowEntryId(flowEntry.flowEntryId().toString());
569 flowEntryObj.setType("flow_entry");
570
571 //
572 // Set the Flow Entry attributes:
573 // - flowEntry.flowEntryMatch()
574 // - flowEntry.flowEntryActions()
575 // - flowEntry.dpid()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800576 // - flowEntry.flowEntryUserState()
577 // - flowEntry.flowEntrySwitchState()
578 // - flowEntry.flowEntryErrorState()
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700579 // - flowEntry.matchInPort()
580 // - flowEntry.matchEthernetFrameType()
581 // - flowEntry.matchSrcIPv4Net()
582 // - flowEntry.matchDstIPv4Net()
583 // - flowEntry.matchSrcMac()
584 // - flowEntry.matchDstMac()
585 // - flowEntry.actionOutput()
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800586 //
587 flowEntryObj.setSwitchDpid(flowEntry.dpid().toString());
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700588 if (flowEntry.flowEntryMatch().matchInPort())
589 flowEntryObj.setMatchInPort(flowEntry.flowEntryMatch().inPort().value());
590 if (flowEntry.flowEntryMatch().matchEthernetFrameType())
591 flowEntryObj.setMatchEthernetFrameType(flowEntry.flowEntryMatch().ethernetFrameType());
592 if (flowEntry.flowEntryMatch().matchSrcIPv4Net())
593 flowEntryObj.setMatchSrcIPv4Net(flowEntry.flowEntryMatch().srcIPv4Net().toString());
594 if (flowEntry.flowEntryMatch().matchDstIPv4Net())
595 flowEntryObj.setMatchDstIPv4Net(flowEntry.flowEntryMatch().dstIPv4Net().toString());
596 if (flowEntry.flowEntryMatch().matchSrcMac())
597 flowEntryObj.setMatchSrcMac(flowEntry.flowEntryMatch().srcMac().toString());
598 if (flowEntry.flowEntryMatch().matchDstMac())
599 flowEntryObj.setMatchDstMac(flowEntry.flowEntryMatch().dstMac().toString());
600
601 for (FlowEntryAction fa : flowEntry.flowEntryActions()) {
602 if (fa.actionOutput() != null)
603 flowEntryObj.setActionOutput(fa.actionOutput().port().value());
604 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800605 // TODO: Hacks with hard-coded state names!
606 if (found)
607 flowEntryObj.setUserState("FE_USER_MODIFY");
608 else
609 flowEntryObj.setUserState("FE_USER_ADD");
610 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
611 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800612 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800613 // and FlowEntryErrorState.
614 //
615
616 // Flow Entries edges:
617 // Flow
618 // NextFE
619 // InPort
620 // OutPort
621 // Switch
622 if (! found)
623 flowObj.addFlowEntry(flowEntryObj);
624 }
625 conn.endTx(Transaction.COMMIT);
626
627 //
628 // TODO: We need a proper Flow ID allocation mechanism.
629 //
630 flowId.setValue(flowPath.flowId().value());
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700631
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800632 return true;
633 }
634
635 /**
636 * Delete a previously added flow.
637 *
638 * @param flowId the Flow ID of the flow to delete.
639 * @return true on success, otherwise false.
640 */
641 @Override
642 public boolean deleteFlow(FlowId flowId) {
Pavlin Radoslavov571cff92013-03-20 02:01:32 -0700643 if (flowId.value() == measurementFlowId) {
644 modifiedMeasurementFlowTime = System.nanoTime();
645 }
646
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800647 IFlowPath flowObj = null;
648 //
649 // We just mark the entries for deletion,
650 // and let the switches remove each individual entry after
651 // it has been removed from the switches.
652 //
653 try {
654 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
655 != null) {
656 log.debug("Deleting FlowPath with FlowId {}: found existing FlowPath",
657 flowId.toString());
658 } else {
659 log.debug("Deleting FlowPath with FlowId {}: FlowPath not found",
660 flowId.toString());
661 }
662 } catch (Exception e) {
663 // TODO: handle exceptions
664 conn.endTx(Transaction.ROLLBACK);
665 log.error(":deleteFlow FlowId:{} failed", flowId.toString());
666 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700667 if (flowObj == null) {
668 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800669 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700670 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800671
672 //
673 // Find and mark for deletion all Flow Entries
674 //
675 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
676 boolean empty = true; // TODO: an ugly hack
677 for (IFlowEntry flowEntryObj : flowEntries) {
678 empty = false;
679 // flowObj.removeFlowEntry(flowEntryObj);
680 // conn.utils().removeFlowEntry(conn, flowEntryObj);
681 flowEntryObj.setUserState("FE_USER_DELETE");
682 flowEntryObj.setSwitchState("FE_SWITCH_NOT_UPDATED");
683 }
684 // Remove from the database empty flows
685 if (empty)
686 conn.utils().removeFlowPath(conn, flowObj);
687 conn.endTx(Transaction.COMMIT);
688
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800689 return true;
690 }
691
692 /**
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700693 * Clear the state for a previously added flow.
694 *
695 * @param flowId the Flow ID of the flow to clear.
696 * @return true on success, otherwise false.
697 */
698 @Override
699 public boolean clearFlow(FlowId flowId) {
700 IFlowPath flowObj = null;
701 try {
702 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
703 != null) {
704 log.debug("Clearing FlowPath with FlowId {}: found existing FlowPath",
705 flowId.toString());
706 } else {
707 log.debug("Clearing FlowPath with FlowId {}: FlowPath not found",
708 flowId.toString());
709 }
710 } catch (Exception e) {
711 // TODO: handle exceptions
712 conn.endTx(Transaction.ROLLBACK);
713 log.error(":clearFlow FlowId:{} failed", flowId.toString());
714 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700715 if (flowObj == null) {
716 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700717 return true; // OK: No such flow
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700718 }
Pavlin Radoslavov916832f2013-03-14 17:48:41 -0700719
720 //
721 // Remove all Flow Entries
722 //
723 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
724 for (IFlowEntry flowEntryObj : flowEntries) {
725 flowObj.removeFlowEntry(flowEntryObj);
726 conn.utils().removeFlowEntry(conn, flowEntryObj);
727 }
728 // Remove the Flow itself
729 conn.utils().removeFlowPath(conn, flowObj);
730 conn.endTx(Transaction.COMMIT);
731
732 return true;
733 }
734
735 /**
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800736 * Get a previously added flow.
737 *
738 * @param flowId the Flow ID of the flow to get.
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800739 * @return the Flow Path if found, otherwise null.
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800740 */
741 @Override
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800742 public FlowPath getFlow(FlowId flowId) {
743 IFlowPath flowObj = null;
744 try {
745 if ((flowObj = conn.utils().searchFlowPath(conn, flowId))
746 != null) {
747 log.debug("Get FlowPath with FlowId {}: found existing FlowPath",
748 flowId.toString());
749 } else {
750 log.debug("Get FlowPath with FlowId {}: FlowPath not found",
751 flowId.toString());
752 }
753 } catch (Exception e) {
754 // TODO: handle exceptions
755 conn.endTx(Transaction.ROLLBACK);
756 log.error(":getFlow FlowId:{} failed", flowId.toString());
757 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700758 if (flowObj == null) {
759 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800760 return null; // Flow not found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700761 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800762
763 //
764 // Extract the Flow state
765 //
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800766 FlowPath flowPath = extractFlowPath(flowObj);
767 conn.endTx(Transaction.COMMIT);
768
769 return flowPath;
770 }
771
772 /**
773 * Get all previously added flows by a specific installer for a given
774 * data path endpoints.
775 *
776 * @param installerId the Caller ID of the installer of the flow to get.
777 * @param dataPathEndpoints the data path endpoints of the flow to get.
778 * @return the Flow Paths if found, otherwise null.
779 */
780 @Override
781 public ArrayList<FlowPath> getAllFlows(CallerId installerId,
782 DataPathEndpoints dataPathEndpoints) {
783 //
784 // TODO: The implementation below is not optimal:
785 // We fetch all flows, and then return only the subset that match
786 // the query conditions.
787 // We should use the appropriate Titan/Gremlin query to filter-out
788 // the flows as appropriate.
789 //
790 ArrayList<FlowPath> allFlows = getAllFlows();
791
792 if (allFlows == null) {
793 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
794 return null;
795 }
796
797 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
798 for (FlowPath flow : allFlows) {
799 //
800 // TODO: String-based comparison is sub-optimal.
801 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800802 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800803 //
804 if (! flow.installerId().toString().equals(installerId.toString()))
805 continue;
806 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
807 continue;
808 }
809 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
810 continue;
811 }
812 flowPaths.add(flow);
813 }
814
815 if (flowPaths.isEmpty()) {
816 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: no FlowPaths found", installerId, dataPathEndpoints);
817 flowPaths = null;
818 } else {
819 log.debug("Get FlowPaths for installerId{} and dataPathEndpoints{}: FlowPaths are found", installerId, dataPathEndpoints);
820 }
821
822 return flowPaths;
823 }
824
825 /**
826 * Get all installed flows by all installers for given data path endpoints.
827 *
828 * @param dataPathEndpoints the data path endpoints of the flows to get.
829 * @return the Flow Paths if found, otherwise null.
830 */
831 @Override
832 public ArrayList<FlowPath> getAllFlows(DataPathEndpoints dataPathEndpoints) {
833 //
834 // TODO: The implementation below is not optimal:
835 // We fetch all flows, and then return only the subset that match
836 // the query conditions.
837 // We should use the appropriate Titan/Gremlin query to filter-out
838 // the flows as appropriate.
839 //
840 ArrayList<FlowPath> allFlows = getAllFlows();
841
842 if (allFlows == null) {
843 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
844 return null;
845 }
846
847 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
848 for (FlowPath flow : allFlows) {
849 //
850 // TODO: String-based comparison is sub-optimal.
851 // We are using it for now to save us the extra work of
Pavlin Radoslavovc4e76a62013-03-06 10:52:41 -0800852 // implementing the "equals()" and "hashCode()" methods.
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800853 //
854 if (! flow.dataPath().srcPort().toString().equals(dataPathEndpoints.srcPort().toString())) {
855 continue;
856 }
857 if (! flow.dataPath().dstPort().toString().equals(dataPathEndpoints.dstPort().toString())) {
858 continue;
859 }
860 flowPaths.add(flow);
861 }
862
863 if (flowPaths.isEmpty()) {
864 log.debug("Get FlowPaths for dataPathEndpoints{}: no FlowPaths found", dataPathEndpoints);
865 flowPaths = null;
866 } else {
867 log.debug("Get FlowPaths for dataPathEndpoints{}: FlowPaths are found", dataPathEndpoints);
868 }
869
870 return flowPaths;
871 }
872
873 /**
874 * Get all installed flows by all installers.
875 *
876 * @return the Flow Paths if found, otherwise null.
877 */
878 @Override
879 public ArrayList<FlowPath> getAllFlows() {
880 Iterable<IFlowPath> flowPathsObj = null;
881
882 try {
883 if ((flowPathsObj = conn.utils().getAllFlowPaths(conn)) != null) {
884 log.debug("Get all FlowPaths: found FlowPaths");
885 } else {
886 log.debug("Get all FlowPaths: no FlowPaths found");
887 }
888 } catch (Exception e) {
889 // TODO: handle exceptions
890 conn.endTx(Transaction.ROLLBACK);
891 log.error(":getAllFlowPaths failed");
892 }
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700893 if ((flowPathsObj == null) || (flowPathsObj.iterator().hasNext() == false)) {
894 conn.endTx(Transaction.COMMIT);
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800895 return null; // No Flows found
Pavlin Radoslavov89c8f432013-03-15 18:50:46 -0700896 }
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800897
898 ArrayList<FlowPath> flowPaths = new ArrayList<FlowPath>();
899 for (IFlowPath flowObj : flowPathsObj) {
900 //
901 // Extract the Flow state
902 //
903 FlowPath flowPath = extractFlowPath(flowObj);
904 flowPaths.add(flowPath);
905 }
906
907 conn.endTx(Transaction.COMMIT);
908
909 return flowPaths;
910 }
911
912 /**
913 * Extract Flow Path State from a Titan Database Object @ref IFlowPath.
914 *
915 * @param flowObj the object to extract the Flow Path State from.
916 * @return the extracted Flow Path State.
917 */
918 private FlowPath extractFlowPath(IFlowPath flowObj) {
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800919 FlowPath flowPath = new FlowPath();
Pavlin Radoslavov706df052013-03-06 10:49:07 -0800920
921 //
922 // Extract the Flow state
923 //
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800924 flowPath.setFlowId(new FlowId(flowObj.getFlowId()));
925 flowPath.setInstallerId(new CallerId(flowObj.getInstallerId()));
926 flowPath.dataPath().srcPort().setDpid(new Dpid(flowObj.getSrcSwitch()));
927 flowPath.dataPath().srcPort().setPort(new Port(flowObj.getSrcPort()));
928 flowPath.dataPath().dstPort().setDpid(new Dpid(flowObj.getDstSwitch()));
929 flowPath.dataPath().dstPort().setPort(new Port(flowObj.getDstPort()));
930
931 //
932 // Extract all Flow Entries
933 //
934 Iterable<IFlowEntry> flowEntries = flowObj.getFlowEntries();
935 for (IFlowEntry flowEntryObj : flowEntries) {
936 FlowEntry flowEntry = new FlowEntry();
937 flowEntry.setFlowEntryId(new FlowEntryId(flowEntryObj.getFlowEntryId()));
938 flowEntry.setDpid(new Dpid(flowEntryObj.getSwitchDpid()));
Pavlin Radoslavove2f0de82013-03-12 01:39:30 -0700939
940 //
941 // Extract the match conditions
942 //
943 FlowEntryMatch match = new FlowEntryMatch();
944 Short matchInPort = flowEntryObj.getMatchInPort();
945 if (matchInPort != null)
946 match.enableInPort(new Port(matchInPort));
947 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
948 if (matchEthernetFrameType != null)
949 match.enableEthernetFrameType(matchEthernetFrameType);
950 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
951 if (matchSrcIPv4Net != null)
952 match.enableSrcIPv4Net(new IPv4Net(matchSrcIPv4Net));
953 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
954 if (matchDstIPv4Net != null)
955 match.enableDstIPv4Net(new IPv4Net(matchDstIPv4Net));
956 String matchSrcMac = flowEntryObj.getMatchSrcMac();
957 if (matchSrcMac != null)
958 match.enableSrcMac(MACAddress.valueOf(matchSrcMac));
959 String matchDstMac = flowEntryObj.getMatchDstMac();
960 if (matchDstMac != null)
961 match.enableDstMac(MACAddress.valueOf(matchDstMac));
962 flowEntry.setFlowEntryMatch(match);
963
964 //
965 // Extract the actions
966 //
967 ArrayList<FlowEntryAction> actions = new ArrayList<FlowEntryAction>();
968 Short actionOutputPort = flowEntryObj.getActionOutput();
969 if (actionOutputPort != null) {
970 FlowEntryAction action = new FlowEntryAction();
971 action.setActionOutput(new Port(actionOutputPort));
972 actions.add(action);
973 }
974 flowEntry.setFlowEntryActions(actions);
975
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800976 String userState = flowEntryObj.getUserState();
977 flowEntry.setFlowEntryUserState(FlowEntryUserState.valueOf(userState));
978 String switchState = flowEntryObj.getSwitchState();
979 flowEntry.setFlowEntrySwitchState(FlowEntrySwitchState.valueOf(switchState));
980 //
Pavlin Radoslavovede97582013-03-08 18:57:28 -0800981 // TODO: Take care of the FlowEntryMatch, FlowEntryAction set,
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800982 // and FlowEntryErrorState.
983 //
984 flowPath.dataPath().flowEntries().add(flowEntry);
985 }
Pavlin Radoslavovb6f53542013-03-01 16:02:14 -0800986
987 return flowPath;
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800988 }
Pavlin Radoslavov9e5344c2013-02-18 09:58:30 -0800989}