blob: 2511a3fbc66bae2cc23263252674a4de53241382 [file] [log] [blame]
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -07001package net.onrc.onos.ofcontroller.flowmanager;
2
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -07003import java.io.IOException;
Naoki Shiota7d0cf272013-11-05 10:18:12 -08004import java.util.ArrayDeque;
5import java.util.ArrayList;
6import java.util.EnumSet;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -07007import java.util.HashMap;
Naoki Shiota7d0cf272013-11-05 10:18:12 -08008import java.util.List;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -07009import java.util.Map;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080010import java.util.Set;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070011
Naoki Shiota7d0cf272013-11-05 10:18:12 -080012import org.openflow.protocol.*;
13import org.openflow.protocol.action.*;
14import org.openflow.protocol.factory.BasicFactory;
15import org.slf4j.Logger;
16import org.slf4j.LoggerFactory;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070017
18import net.floodlightcontroller.core.FloodlightContext;
19import net.floodlightcontroller.core.IOFSwitch;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080020import net.floodlightcontroller.util.OFMessageDamper;
21import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
22import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
23import net.onrc.onos.ofcontroller.util.FlowEntryAction;
24import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
25import net.onrc.onos.ofcontroller.util.FlowEntryActions;
26import net.onrc.onos.ofcontroller.util.FlowEntryId;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070027
28/**
29 * FlowPusher intermediates flow_mod sent from FlowManager/FlowSync to switches.
30 * FlowPusher controls the rate of sending flow_mods so that connection doesn't overflow.
31 * @author Naoki Shiota
32 *
33 */
34public class FlowPusher {
Naoki Shiota7d0cf272013-11-05 10:18:12 -080035 private final static Logger log = LoggerFactory.getLogger(FlowPusher.class);
36
37 // NOTE: Below are moved from FlowManager.
38 // TODO: Values copied from elsewhere (class LearningSwitch).
39 // The local copy should go away!
40 //
41 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
42 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080043
44 protected static final long SLEEP_MILLI_SEC = 3;
45 protected static final int SLEEP_NANO_SEC = 0;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080046
47 public static final short PRIORITY_DEFAULT = 100;
48 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
49 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080050
51
Naoki Shiota7d0cf272013-11-05 10:18:12 -080052
53 public enum QueueState {
54 READY,
55 SUSPENDED,
56 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070057
Naoki Shiota7d0cf272013-11-05 10:18:12 -080058 private class SwitchQueue extends ArrayDeque<OFMessage> {
59 QueueState state;
60
61 // Max rate of sending message (bytes/sec). 0 implies no limitation.
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080062 long max_rate = Long.MAX_VALUE;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070063 long last_sent_time = 0;
64 long last_sent_size = 0;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080065
66 /**
67 * Check if sending rate is within the rate
68 * @param current Current time
69 * @return true if within the rate
70 */
71 boolean isSendable(long current) {
72 long rate = last_sent_size / (current - last_sent_time);
73
74 if (rate < max_rate) {
75 return true;
76 } else {
77 return false;
78 }
79 }
80
81 void updateRate(long current, OFMessage msg) {
82 last_sent_time = current;
83 last_sent_size = msg.getLengthU();
84 }
85
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070086 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -080087
88 private Map<IOFSwitch,SwitchQueue> queues
89 = new HashMap<IOFSwitch,SwitchQueue>();
90
91 private OFMessageDamper messageDamper;
Naoki Shiotacf1acca2013-10-31 11:40:32 -070092
Naoki Shiota7d0cf272013-11-05 10:18:12 -080093 private FloodlightContext context = null;
94 private BasicFactory factory = null;
95 private Thread thread = null;
96
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080097 private boolean isStopped = false;
98 private boolean isMsgAdded = false;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080099
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700100 private class FlowPusherProcess implements Runnable {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800101
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700102 @Override
103 public void run() {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800104 log.debug("Begin Flow Pusher Process");
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700105
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700106 while (true) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800107 Set< Map.Entry<IOFSwitch,SwitchQueue> > entries;
108 synchronized (queues) {
109 entries = queues.entrySet();
110 }
111
112 // Set taint flag to false at this moment.
113 isMsgAdded = false;
114
115 for (Map.Entry<IOFSwitch,SwitchQueue> entry : entries) {
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800116 IOFSwitch sw = entry.getKey();
117 SwitchQueue queue = entry.getValue();
118
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700119 // Skip if queue is suspended
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800120 if (sw == null || queue == null ||
121 queue.state != QueueState.READY) {
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700122 continue;
123 }
124
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800125 synchronized (queue) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800126 log.debug("Queue size : {}", queue.size());
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800127
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800128 // check sending rate and determine it to be sent or not
129 long current_time = System.nanoTime();
130
131 if (queue.isSendable(current_time)) {
132 // TODO send multiple messages at once
133 while (! queue.isEmpty()) {
134 OFMessage msg = queue.poll();
135
136 // if need to send, call IOFSwitch#write()
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800137 try {
138 messageDamper.write(sw, msg, context);
139 queue.updateRate(current_time, msg);
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800140 log.debug("Pusher sends message : {}", msg);
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800141 } catch (IOException e) {
142 // TODO Auto-generated catch block
143 e.printStackTrace();
144 }
145 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700146 }
147 }
148 }
149
150 // sleep while all queues are empty
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800151 while (! isMsgAdded) {
152 if (isStopped) {
153 log.debug("Pusher Process finished.");
154 return;
155 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800156
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800157 try {
158 Thread.sleep(SLEEP_MILLI_SEC, SLEEP_NANO_SEC);
159 } catch (InterruptedException e) {
160 // TODO Auto-generated catch block
161 e.printStackTrace();
162 }
163 }
164
165 log.debug("Exit sleep loop.");
166
167 if (isStopped) {
168 log.debug("Pusher Process finished.");
169 return;
170 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700171 }
172 }
173 }
174
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800175 public void init(FloodlightContext context, BasicFactory factory, OFMessageDamper damper) {
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700176 this.context = context;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800177 this.factory = factory;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800178
179 if (damper != null) {
180 messageDamper = damper;
181 } else {
182 // use default value
183 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
184 EnumSet.of(OFType.FLOW_MOD),
185 OFMESSAGE_DAMPER_TIMEOUT);
186 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700187 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800188 /**
189 * Begin processing queue.
190 */
191 public void start() {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800192 if (factory == null) {
193 log.error("FlowPusher not yet initialized.");
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800194 return;
195 }
196
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700197 thread = new Thread(new FlowPusherProcess());
198 thread.start();
199 }
200
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800201 /**
202 * Suspend processing a queue related to given switch.
203 * @param sw
204 */
205 public void suspend(IOFSwitch sw) {
206 SwitchQueue queue = getQueue(sw);
207
208 if (queue == null) {
209 return;
210 }
211
212 synchronized (queue) {
213 if (queue.state == QueueState.READY) {
214 queue.state = QueueState.SUSPENDED;
215 }
216 }
217 }
218
219 /**
220 * Resume processing a queue related to given switch.
221 */
222 public void resume(IOFSwitch sw) {
223 SwitchQueue queue = getQueue(sw);
224
225 if (queue == null) {
226 return;
227 }
228
229 synchronized (queue) {
230 if (queue.state == QueueState.SUSPENDED) {
231 queue.state = QueueState.READY;
232 }
233 }
234 }
235
236 /**
237 * End processing queue and exit thread.
238 */
239 public void stop() {
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700240 if (thread != null && thread.isAlive()) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800241 isStopped = true;
242 }
243 }
244
245 public void setRate(IOFSwitch sw, long rate) {
246 SwitchQueue queue = getQueue(sw);
247 if (queue == null) {
248 return;
249 }
250
251 if (rate > 0) {
252 queue.max_rate = rate;
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700253 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700254 }
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700255
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800256 /**
257 * Add OFMessage to the queue related to given switch.
258 * @param sw
259 * @param msg
260 */
261 public boolean send(IOFSwitch sw, OFMessage msg) {
262 SwitchQueue queue = getQueue(sw);
263 if (queue == null) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800264 queue = new SwitchQueue();
265 queue.state = QueueState.READY;
266 synchronized (queues) {
267 queues.put(sw, queue);
268 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800269 }
270
271 synchronized (queue) {
272 queue.add(msg);
273 }
274
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800275 isMsgAdded = true;
276
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800277 return true;
278 }
279
280 /**
281 * Create OFMessage from given flow information and add it to the queue.
282 * @param sw
283 * @param flowObj
284 * @param flowEntryObj
285 * @return
286 */
287 public boolean send(IOFSwitch sw, IFlowPath flowObj, IFlowEntry flowEntryObj) {
288 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
289 if (flowEntryIdStr == null)
290 return false;
291 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
292 String userState = flowEntryObj.getUserState();
293 if (userState == null)
294 return false;
295
296 //
297 // Create the Open Flow Flow Modification Entry to push
298 //
299 OFFlowMod fm = (OFFlowMod)factory.getMessage(OFType.FLOW_MOD);
300 long cookie = flowEntryId.value();
301
302 short flowModCommand = OFFlowMod.OFPFC_ADD;
303 if (userState.equals("FE_USER_ADD")) {
304 flowModCommand = OFFlowMod.OFPFC_ADD;
305 } else if (userState.equals("FE_USER_MODIFY")) {
306 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
307 } else if (userState.equals("FE_USER_DELETE")) {
308 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
309 } else {
310 // Unknown user state. Ignore the entry
311 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
312 flowEntryId.toString(), userState);
313 return false;
314 }
315
316 //
317 // Fetch the match conditions.
318 //
319 // NOTE: The Flow matching conditions common for all Flow Entries are
320 // used ONLY if a Flow Entry does NOT have the corresponding matching
321 // condition set.
322 //
323 OFMatch match = new OFMatch();
324 match.setWildcards(OFMatch.OFPFW_ALL);
325
326 // Match the Incoming Port
327 Short matchInPort = flowEntryObj.getMatchInPort();
328 if (matchInPort != null) {
329 match.setInputPort(matchInPort);
330 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
331 }
332
333 // Match the Source MAC address
334 String matchSrcMac = flowEntryObj.getMatchSrcMac();
335 if (matchSrcMac == null)
336 matchSrcMac = flowObj.getMatchSrcMac();
337 if (matchSrcMac != null) {
338 match.setDataLayerSource(matchSrcMac);
339 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
340 }
341
342 // Match the Destination MAC address
343 String matchDstMac = flowEntryObj.getMatchDstMac();
344 if (matchDstMac == null)
345 matchDstMac = flowObj.getMatchDstMac();
346 if (matchDstMac != null) {
347 match.setDataLayerDestination(matchDstMac);
348 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
349 }
350
351 // Match the Ethernet Frame Type
352 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
353 if (matchEthernetFrameType == null)
354 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
355 if (matchEthernetFrameType != null) {
356 match.setDataLayerType(matchEthernetFrameType);
357 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
358 }
359
360 // Match the VLAN ID
361 Short matchVlanId = flowEntryObj.getMatchVlanId();
362 if (matchVlanId == null)
363 matchVlanId = flowObj.getMatchVlanId();
364 if (matchVlanId != null) {
365 match.setDataLayerVirtualLan(matchVlanId);
366 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
367 }
368
369 // Match the VLAN priority
370 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
371 if (matchVlanPriority == null)
372 matchVlanPriority = flowObj.getMatchVlanPriority();
373 if (matchVlanPriority != null) {
374 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
375 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
376 }
377
378 // Match the Source IPv4 Network prefix
379 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
380 if (matchSrcIPv4Net == null)
381 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
382 if (matchSrcIPv4Net != null) {
383 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
384 }
385
386 // Match the Destination IPv4 Network prefix
387 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
388 if (matchDstIPv4Net == null)
389 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
390 if (matchDstIPv4Net != null) {
391 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
392 }
393
394 // Match the IP protocol
395 Byte matchIpProto = flowEntryObj.getMatchIpProto();
396 if (matchIpProto == null)
397 matchIpProto = flowObj.getMatchIpProto();
398 if (matchIpProto != null) {
399 match.setNetworkProtocol(matchIpProto);
400 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
401 }
402
403 // Match the IP ToS (DSCP field, 6 bits)
404 Byte matchIpToS = flowEntryObj.getMatchIpToS();
405 if (matchIpToS == null)
406 matchIpToS = flowObj.getMatchIpToS();
407 if (matchIpToS != null) {
408 match.setNetworkTypeOfService(matchIpToS);
409 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
410 }
411
412 // Match the Source TCP/UDP port
413 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
414 if (matchSrcTcpUdpPort == null)
415 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
416 if (matchSrcTcpUdpPort != null) {
417 match.setTransportSource(matchSrcTcpUdpPort);
418 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
419 }
420
421 // Match the Destination TCP/UDP port
422 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
423 if (matchDstTcpUdpPort == null)
424 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
425 if (matchDstTcpUdpPort != null) {
426 match.setTransportDestination(matchDstTcpUdpPort);
427 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
428 }
429
430 //
431 // Fetch the actions
432 //
433 Short actionOutputPort = null;
434 List<OFAction> openFlowActions = new ArrayList<OFAction>();
435 int actionsLen = 0;
436 FlowEntryActions flowEntryActions = null;
437 String actionsStr = flowEntryObj.getActions();
438 if (actionsStr != null)
439 flowEntryActions = new FlowEntryActions(actionsStr);
440 else
441 flowEntryActions = new FlowEntryActions();
442 for (FlowEntryAction action : flowEntryActions.actions()) {
443 ActionOutput actionOutput = action.actionOutput();
444 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
445 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
446 ActionStripVlan actionStripVlan = action.actionStripVlan();
447 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
448 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
449 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
450 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
451 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
452 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
453 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
454 ActionEnqueue actionEnqueue = action.actionEnqueue();
455
456 if (actionOutput != null) {
457 actionOutputPort = actionOutput.port().value();
458 // XXX: The max length is hard-coded for now
459 OFActionOutput ofa =
460 new OFActionOutput(actionOutput.port().value(),
461 (short)0xffff);
462 openFlowActions.add(ofa);
463 actionsLen += ofa.getLength();
464 }
465
466 if (actionSetVlanId != null) {
467 OFActionVirtualLanIdentifier ofa =
468 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
469 openFlowActions.add(ofa);
470 actionsLen += ofa.getLength();
471 }
472
473 if (actionSetVlanPriority != null) {
474 OFActionVirtualLanPriorityCodePoint ofa =
475 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
476 openFlowActions.add(ofa);
477 actionsLen += ofa.getLength();
478 }
479
480 if (actionStripVlan != null) {
481 if (actionStripVlan.stripVlan() == true) {
482 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
483 openFlowActions.add(ofa);
484 actionsLen += ofa.getLength();
485 }
486 }
487
488 if (actionSetEthernetSrcAddr != null) {
489 OFActionDataLayerSource ofa =
490 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
491 openFlowActions.add(ofa);
492 actionsLen += ofa.getLength();
493 }
494
495 if (actionSetEthernetDstAddr != null) {
496 OFActionDataLayerDestination ofa =
497 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
498 openFlowActions.add(ofa);
499 actionsLen += ofa.getLength();
500 }
501
502 if (actionSetIPv4SrcAddr != null) {
503 OFActionNetworkLayerSource ofa =
504 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
505 openFlowActions.add(ofa);
506 actionsLen += ofa.getLength();
507 }
508
509 if (actionSetIPv4DstAddr != null) {
510 OFActionNetworkLayerDestination ofa =
511 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
512 openFlowActions.add(ofa);
513 actionsLen += ofa.getLength();
514 }
515
516 if (actionSetIpToS != null) {
517 OFActionNetworkTypeOfService ofa =
518 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
519 openFlowActions.add(ofa);
520 actionsLen += ofa.getLength();
521 }
522
523 if (actionSetTcpUdpSrcPort != null) {
524 OFActionTransportLayerSource ofa =
525 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
526 openFlowActions.add(ofa);
527 actionsLen += ofa.getLength();
528 }
529
530 if (actionSetTcpUdpDstPort != null) {
531 OFActionTransportLayerDestination ofa =
532 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
533 openFlowActions.add(ofa);
534 actionsLen += ofa.getLength();
535 }
536
537 if (actionEnqueue != null) {
538 OFActionEnqueue ofa =
539 new OFActionEnqueue(actionEnqueue.port().value(),
540 actionEnqueue.queueId());
541 openFlowActions.add(ofa);
542 actionsLen += ofa.getLength();
543 }
544 }
545
546 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
547 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
548 .setPriority(PRIORITY_DEFAULT)
549 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
550 .setCookie(cookie)
551 .setCommand(flowModCommand)
552 .setMatch(match)
553 .setActions(openFlowActions)
554 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
555 fm.setOutPort(OFPort.OFPP_NONE.getValue());
556 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
557 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
558 if (actionOutputPort != null)
559 fm.setOutPort(actionOutputPort);
560 }
561
562 //
563 // TODO: Set the following flag
564 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
565 // See method ForwardingBase::pushRoute()
566 //
567
568 //
569 // Write the message to the switch
570 //
571 log.debug("MEASUREMENT: Installing flow entry " + userState +
572 " into switch DPID: " +
573 sw.getStringId() +
574 " flowEntryId: " + flowEntryId.toString() +
575 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
576 " inPort: " + matchInPort + " outPort: " + actionOutputPort
577 );
578 send(sw,fm);
579 //
580 // TODO: We should use the OpenFlow Barrier mechanism
581 // to check for errors, and update the SwitchState
582 // for a flow entry after the Barrier message is
583 // is received.
584 //
585 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
586
587 return true;
588 }
589
590 private SwitchQueue getQueue(IOFSwitch sw) {
591 if (sw == null) {
592 return null;
593 }
594
595 return queues.get(sw);
596 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700597}