blob: eef60a127d9e421d6fc40049ad8d1139a0f28849 [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 Shiota2e2fc2b2013-11-12 11:21:36 -080020import net.floodlightcontroller.util.MACAddress;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080021import net.floodlightcontroller.util.OFMessageDamper;
22import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowEntry;
23import net.onrc.onos.ofcontroller.core.INetMapTopologyObjects.IFlowPath;
24import net.onrc.onos.ofcontroller.util.FlowEntryAction;
25import net.onrc.onos.ofcontroller.util.FlowEntryAction.*;
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -080026import net.onrc.onos.ofcontroller.util.FlowEntry;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080027import net.onrc.onos.ofcontroller.util.FlowEntryActions;
28import net.onrc.onos.ofcontroller.util.FlowEntryId;
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -080029import net.onrc.onos.ofcontroller.util.FlowEntryMatch;
30import net.onrc.onos.ofcontroller.util.FlowEntryUserState;
31import net.onrc.onos.ofcontroller.util.FlowPath;
32import net.onrc.onos.ofcontroller.util.IPv4Net;
33import net.onrc.onos.ofcontroller.util.Port;
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070034
35/**
36 * FlowPusher intermediates flow_mod sent from FlowManager/FlowSync to switches.
37 * FlowPusher controls the rate of sending flow_mods so that connection doesn't overflow.
38 * @author Naoki Shiota
39 *
40 */
41public class FlowPusher {
Naoki Shiota7d0cf272013-11-05 10:18:12 -080042 private final static Logger log = LoggerFactory.getLogger(FlowPusher.class);
43
44 // NOTE: Below are moved from FlowManager.
45 // TODO: Values copied from elsewhere (class LearningSwitch).
46 // The local copy should go away!
47 //
48 protected static final int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
49 protected static final int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
Naoki Shiota5c8d19f2013-11-05 15:52:38 -080050
51 protected static final long SLEEP_MILLI_SEC = 3;
52 protected static final int SLEEP_NANO_SEC = 0;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080053
54 public static final short PRIORITY_DEFAULT = 100;
55 public static final short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 0; // infinity
56 public static final short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
57
58 public enum QueueState {
59 READY,
60 SUSPENDED,
61 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070062
Naoki Shiota7d0cf272013-11-05 10:18:12 -080063 private class SwitchQueue extends ArrayDeque<OFMessage> {
64 QueueState state;
65
66 // Max rate of sending message (bytes/sec). 0 implies no limitation.
Naoki Shiota8ee48d52013-11-11 15:51:17 -080067 long max_rate = 0; // 0 indicates no limitation
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070068 long last_sent_time = 0;
69 long last_sent_size = 0;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080070
71 /**
72 * Check if sending rate is within the rate
73 * @param current Current time
74 * @return true if within the rate
75 */
76 boolean isSendable(long current) {
Naoki Shiota8ee48d52013-11-11 15:51:17 -080077 if (max_rate == 0) {
78 // no limitation
79 return true;
80 }
81
Naoki Shiota7d0cf272013-11-05 10:18:12 -080082 long rate = last_sent_size / (current - last_sent_time);
83
84 if (rate < max_rate) {
85 return true;
86 } else {
87 return false;
88 }
89 }
90
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -080091 void logSentData(long current, long size) {
Naoki Shiota7d0cf272013-11-05 10:18:12 -080092 last_sent_time = current;
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -080093 last_sent_size = size;
Naoki Shiota7d0cf272013-11-05 10:18:12 -080094 }
95
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -070096 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -080097
98 private Map<IOFSwitch,SwitchQueue> queues
99 = new HashMap<IOFSwitch,SwitchQueue>();
100
101 private OFMessageDamper messageDamper;
Naoki Shiotacf1acca2013-10-31 11:40:32 -0700102
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800103 private FloodlightContext context = null;
104 private BasicFactory factory = null;
105 private Thread thread = null;
106
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800107 private boolean isStopped = false;
108 private boolean isMsgAdded = false;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800109
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700110 private class FlowPusherProcess implements Runnable {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800111
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700112 @Override
113 public void run() {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800114 log.debug("Begin Flow Pusher Process");
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700115
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700116 while (true) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800117 Set< Map.Entry<IOFSwitch,SwitchQueue> > entries;
118 synchronized (queues) {
119 entries = queues.entrySet();
120 }
121
122 // Set taint flag to false at this moment.
123 isMsgAdded = false;
124
125 for (Map.Entry<IOFSwitch,SwitchQueue> entry : entries) {
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800126 IOFSwitch sw = entry.getKey();
127 SwitchQueue queue = entry.getValue();
128
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700129 // Skip if queue is suspended
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800130 if (sw == null || queue == null ||
131 queue.state != QueueState.READY) {
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700132 continue;
133 }
134
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800135 // check sending rate and determine it to be sent or not
136 long current_time = System.nanoTime();
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800137 long size = 0;
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800138
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800139 synchronized (queue) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800140 if (queue.isSendable(current_time)) {
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800141 // TODO limit number of messages to be sent at once
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800142 while (! queue.isEmpty()) {
143 OFMessage msg = queue.poll();
144
145 // if need to send, call IOFSwitch#write()
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800146 try {
147 messageDamper.write(sw, msg, context);
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800148 size += msg.getLength();
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800149 log.debug("Pusher sends message : {}", msg);
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800150 } catch (IOException e) {
151 // TODO Auto-generated catch block
152 e.printStackTrace();
153 }
154 }
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800155 queue.logSentData(current_time, size);
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700156 }
157 }
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800158 sw.flush();
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700159 }
160
161 // sleep while all queues are empty
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800162 while (! (isMsgAdded || isStopped)) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800163 try {
164 Thread.sleep(SLEEP_MILLI_SEC, SLEEP_NANO_SEC);
165 } catch (InterruptedException e) {
166 // TODO Auto-generated catch block
167 e.printStackTrace();
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800168 log.error("Thread.sleep failed");
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800169 }
170 }
171
172 log.debug("Exit sleep loop.");
173
174 if (isStopped) {
175 log.debug("Pusher Process finished.");
176 return;
177 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800178
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700179 }
180 }
181 }
182
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800183 public void init(FloodlightContext context, BasicFactory factory, OFMessageDamper damper) {
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700184 this.context = context;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800185 this.factory = factory;
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800186
187 if (damper != null) {
188 messageDamper = damper;
189 } else {
190 // use default value
191 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
192 EnumSet.of(OFType.FLOW_MOD),
193 OFMESSAGE_DAMPER_TIMEOUT);
194 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700195 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800196 /**
197 * Begin processing queue.
198 */
199 public void start() {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800200 if (factory == null) {
201 log.error("FlowPusher not yet initialized.");
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800202 return;
203 }
204
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700205 thread = new Thread(new FlowPusherProcess());
206 thread.start();
207 }
208
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800209 /**
210 * Suspend processing a queue related to given switch.
211 * @param sw
212 */
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800213 public boolean suspend(IOFSwitch sw) {
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800214 SwitchQueue queue = getQueue(sw);
215
216 if (queue == null) {
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800217 return false;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800218 }
219
220 synchronized (queue) {
221 if (queue.state == QueueState.READY) {
222 queue.state = QueueState.SUSPENDED;
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800223 return true;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800224 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800225 return false;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800226 }
227 }
228
229 /**
230 * Resume processing a queue related to given switch.
231 */
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800232 public boolean resume(IOFSwitch sw) {
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800233 SwitchQueue queue = getQueue(sw);
234
235 if (queue == null) {
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800236 return false;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800237 }
238
239 synchronized (queue) {
240 if (queue.state == QueueState.SUSPENDED) {
241 queue.state = QueueState.READY;
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800242 return true;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800243 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800244 return false;
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800245 }
246 }
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800247
248 public boolean isSuspended(IOFSwitch sw) {
249 SwitchQueue queue = getQueue(sw);
250
251 if (queue == null) {
252 // TODO Is true suitable for this case?
253 return true;
254 }
255
256 return (queue.state == QueueState.SUSPENDED);
257 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800258
259 /**
260 * End processing queue and exit thread.
261 */
262 public void stop() {
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700263 if (thread != null && thread.isAlive()) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800264 isStopped = true;
265 }
266 }
267
268 public void setRate(IOFSwitch sw, long rate) {
269 SwitchQueue queue = getQueue(sw);
270 if (queue == null) {
271 return;
272 }
273
274 if (rate > 0) {
275 queue.max_rate = rate;
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700276 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700277 }
Naoki Shiotac2a699a2013-10-31 15:36:01 -0700278
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800279 /**
280 * Add OFMessage to the queue related to given switch.
281 * @param sw
282 * @param msg
283 */
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800284 public boolean add(IOFSwitch sw, OFMessage msg) {
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800285 SwitchQueue queue = getQueue(sw);
286 if (queue == null) {
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800287 queue = new SwitchQueue();
288 queue.state = QueueState.READY;
289 synchronized (queues) {
290 queues.put(sw, queue);
291 }
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800292 }
293
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800294 log.debug("Message is pushed : {}", msg);
295
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800296 synchronized (queue) {
297 queue.add(msg);
298 }
299
Naoki Shiota5c8d19f2013-11-05 15:52:38 -0800300 isMsgAdded = true;
301
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800302 return true;
303 }
304
305 /**
306 * Create OFMessage from given flow information and add it to the queue.
307 * @param sw
308 * @param flowObj
309 * @param flowEntryObj
310 * @return
311 */
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800312 public boolean add(IOFSwitch sw, IFlowPath flowObj, IFlowEntry flowEntryObj) {
Naoki Shiota8ee48d52013-11-11 15:51:17 -0800313 log.debug("sending : {}, {}", sw, flowObj);
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800314 String flowEntryIdStr = flowEntryObj.getFlowEntryId();
315 if (flowEntryIdStr == null)
316 return false;
317 FlowEntryId flowEntryId = new FlowEntryId(flowEntryIdStr);
318 String userState = flowEntryObj.getUserState();
319 if (userState == null)
320 return false;
321
322 //
323 // Create the Open Flow Flow Modification Entry to push
324 //
325 OFFlowMod fm = (OFFlowMod)factory.getMessage(OFType.FLOW_MOD);
326 long cookie = flowEntryId.value();
327
328 short flowModCommand = OFFlowMod.OFPFC_ADD;
329 if (userState.equals("FE_USER_ADD")) {
330 flowModCommand = OFFlowMod.OFPFC_ADD;
331 } else if (userState.equals("FE_USER_MODIFY")) {
332 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
333 } else if (userState.equals("FE_USER_DELETE")) {
334 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
335 } else {
336 // Unknown user state. Ignore the entry
337 log.debug("Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
338 flowEntryId.toString(), userState);
339 return false;
340 }
341
342 //
343 // Fetch the match conditions.
344 //
345 // NOTE: The Flow matching conditions common for all Flow Entries are
346 // used ONLY if a Flow Entry does NOT have the corresponding matching
347 // condition set.
348 //
349 OFMatch match = new OFMatch();
350 match.setWildcards(OFMatch.OFPFW_ALL);
351
352 // Match the Incoming Port
353 Short matchInPort = flowEntryObj.getMatchInPort();
354 if (matchInPort != null) {
355 match.setInputPort(matchInPort);
356 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
357 }
358
359 // Match the Source MAC address
360 String matchSrcMac = flowEntryObj.getMatchSrcMac();
361 if (matchSrcMac == null)
362 matchSrcMac = flowObj.getMatchSrcMac();
363 if (matchSrcMac != null) {
364 match.setDataLayerSource(matchSrcMac);
365 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
366 }
367
368 // Match the Destination MAC address
369 String matchDstMac = flowEntryObj.getMatchDstMac();
370 if (matchDstMac == null)
371 matchDstMac = flowObj.getMatchDstMac();
372 if (matchDstMac != null) {
373 match.setDataLayerDestination(matchDstMac);
374 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
375 }
376
377 // Match the Ethernet Frame Type
378 Short matchEthernetFrameType = flowEntryObj.getMatchEthernetFrameType();
379 if (matchEthernetFrameType == null)
380 matchEthernetFrameType = flowObj.getMatchEthernetFrameType();
381 if (matchEthernetFrameType != null) {
382 match.setDataLayerType(matchEthernetFrameType);
383 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
384 }
385
386 // Match the VLAN ID
387 Short matchVlanId = flowEntryObj.getMatchVlanId();
388 if (matchVlanId == null)
389 matchVlanId = flowObj.getMatchVlanId();
390 if (matchVlanId != null) {
391 match.setDataLayerVirtualLan(matchVlanId);
392 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
393 }
394
395 // Match the VLAN priority
396 Byte matchVlanPriority = flowEntryObj.getMatchVlanPriority();
397 if (matchVlanPriority == null)
398 matchVlanPriority = flowObj.getMatchVlanPriority();
399 if (matchVlanPriority != null) {
400 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
401 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN_PCP);
402 }
403
404 // Match the Source IPv4 Network prefix
405 String matchSrcIPv4Net = flowEntryObj.getMatchSrcIPv4Net();
406 if (matchSrcIPv4Net == null)
407 matchSrcIPv4Net = flowObj.getMatchSrcIPv4Net();
408 if (matchSrcIPv4Net != null) {
409 match.setFromCIDR(matchSrcIPv4Net, OFMatch.STR_NW_SRC);
410 }
411
412 // Match the Destination IPv4 Network prefix
413 String matchDstIPv4Net = flowEntryObj.getMatchDstIPv4Net();
414 if (matchDstIPv4Net == null)
415 matchDstIPv4Net = flowObj.getMatchDstIPv4Net();
416 if (matchDstIPv4Net != null) {
417 match.setFromCIDR(matchDstIPv4Net, OFMatch.STR_NW_DST);
418 }
419
420 // Match the IP protocol
421 Byte matchIpProto = flowEntryObj.getMatchIpProto();
422 if (matchIpProto == null)
423 matchIpProto = flowObj.getMatchIpProto();
424 if (matchIpProto != null) {
425 match.setNetworkProtocol(matchIpProto);
426 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
427 }
428
429 // Match the IP ToS (DSCP field, 6 bits)
430 Byte matchIpToS = flowEntryObj.getMatchIpToS();
431 if (matchIpToS == null)
432 matchIpToS = flowObj.getMatchIpToS();
433 if (matchIpToS != null) {
434 match.setNetworkTypeOfService(matchIpToS);
435 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
436 }
437
438 // Match the Source TCP/UDP port
439 Short matchSrcTcpUdpPort = flowEntryObj.getMatchSrcTcpUdpPort();
440 if (matchSrcTcpUdpPort == null)
441 matchSrcTcpUdpPort = flowObj.getMatchSrcTcpUdpPort();
442 if (matchSrcTcpUdpPort != null) {
443 match.setTransportSource(matchSrcTcpUdpPort);
444 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
445 }
446
447 // Match the Destination TCP/UDP port
448 Short matchDstTcpUdpPort = flowEntryObj.getMatchDstTcpUdpPort();
449 if (matchDstTcpUdpPort == null)
450 matchDstTcpUdpPort = flowObj.getMatchDstTcpUdpPort();
451 if (matchDstTcpUdpPort != null) {
452 match.setTransportDestination(matchDstTcpUdpPort);
453 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
454 }
455
456 //
457 // Fetch the actions
458 //
459 Short actionOutputPort = null;
460 List<OFAction> openFlowActions = new ArrayList<OFAction>();
461 int actionsLen = 0;
462 FlowEntryActions flowEntryActions = null;
463 String actionsStr = flowEntryObj.getActions();
464 if (actionsStr != null)
465 flowEntryActions = new FlowEntryActions(actionsStr);
466 else
467 flowEntryActions = new FlowEntryActions();
468 for (FlowEntryAction action : flowEntryActions.actions()) {
469 ActionOutput actionOutput = action.actionOutput();
470 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
471 ActionSetVlanPriority actionSetVlanPriority = action.actionSetVlanPriority();
472 ActionStripVlan actionStripVlan = action.actionStripVlan();
473 ActionSetEthernetAddr actionSetEthernetSrcAddr = action.actionSetEthernetSrcAddr();
474 ActionSetEthernetAddr actionSetEthernetDstAddr = action.actionSetEthernetDstAddr();
475 ActionSetIPv4Addr actionSetIPv4SrcAddr = action.actionSetIPv4SrcAddr();
476 ActionSetIPv4Addr actionSetIPv4DstAddr = action.actionSetIPv4DstAddr();
477 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
478 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action.actionSetTcpUdpSrcPort();
479 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action.actionSetTcpUdpDstPort();
480 ActionEnqueue actionEnqueue = action.actionEnqueue();
481
482 if (actionOutput != null) {
483 actionOutputPort = actionOutput.port().value();
484 // XXX: The max length is hard-coded for now
485 OFActionOutput ofa =
486 new OFActionOutput(actionOutput.port().value(),
487 (short)0xffff);
488 openFlowActions.add(ofa);
489 actionsLen += ofa.getLength();
490 }
491
492 if (actionSetVlanId != null) {
493 OFActionVirtualLanIdentifier ofa =
494 new OFActionVirtualLanIdentifier(actionSetVlanId.vlanId());
495 openFlowActions.add(ofa);
496 actionsLen += ofa.getLength();
497 }
498
499 if (actionSetVlanPriority != null) {
500 OFActionVirtualLanPriorityCodePoint ofa =
501 new OFActionVirtualLanPriorityCodePoint(actionSetVlanPriority.vlanPriority());
502 openFlowActions.add(ofa);
503 actionsLen += ofa.getLength();
504 }
505
506 if (actionStripVlan != null) {
507 if (actionStripVlan.stripVlan() == true) {
508 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
509 openFlowActions.add(ofa);
510 actionsLen += ofa.getLength();
511 }
512 }
513
514 if (actionSetEthernetSrcAddr != null) {
515 OFActionDataLayerSource ofa =
516 new OFActionDataLayerSource(actionSetEthernetSrcAddr.addr().toBytes());
517 openFlowActions.add(ofa);
518 actionsLen += ofa.getLength();
519 }
520
521 if (actionSetEthernetDstAddr != null) {
522 OFActionDataLayerDestination ofa =
523 new OFActionDataLayerDestination(actionSetEthernetDstAddr.addr().toBytes());
524 openFlowActions.add(ofa);
525 actionsLen += ofa.getLength();
526 }
527
528 if (actionSetIPv4SrcAddr != null) {
529 OFActionNetworkLayerSource ofa =
530 new OFActionNetworkLayerSource(actionSetIPv4SrcAddr.addr().value());
531 openFlowActions.add(ofa);
532 actionsLen += ofa.getLength();
533 }
534
535 if (actionSetIPv4DstAddr != null) {
536 OFActionNetworkLayerDestination ofa =
537 new OFActionNetworkLayerDestination(actionSetIPv4DstAddr.addr().value());
538 openFlowActions.add(ofa);
539 actionsLen += ofa.getLength();
540 }
541
542 if (actionSetIpToS != null) {
543 OFActionNetworkTypeOfService ofa =
544 new OFActionNetworkTypeOfService(actionSetIpToS.ipToS());
545 openFlowActions.add(ofa);
546 actionsLen += ofa.getLength();
547 }
548
549 if (actionSetTcpUdpSrcPort != null) {
550 OFActionTransportLayerSource ofa =
551 new OFActionTransportLayerSource(actionSetTcpUdpSrcPort.port());
552 openFlowActions.add(ofa);
553 actionsLen += ofa.getLength();
554 }
555
556 if (actionSetTcpUdpDstPort != null) {
557 OFActionTransportLayerDestination ofa =
558 new OFActionTransportLayerDestination(actionSetTcpUdpDstPort.port());
559 openFlowActions.add(ofa);
560 actionsLen += ofa.getLength();
561 }
562
563 if (actionEnqueue != null) {
564 OFActionEnqueue ofa =
565 new OFActionEnqueue(actionEnqueue.port().value(),
566 actionEnqueue.queueId());
567 openFlowActions.add(ofa);
568 actionsLen += ofa.getLength();
569 }
570 }
571
572 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
573 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
574 .setPriority(PRIORITY_DEFAULT)
575 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
576 .setCookie(cookie)
577 .setCommand(flowModCommand)
578 .setMatch(match)
579 .setActions(openFlowActions)
580 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
581 fm.setOutPort(OFPort.OFPP_NONE.getValue());
582 if ((flowModCommand == OFFlowMod.OFPFC_DELETE) ||
583 (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
584 if (actionOutputPort != null)
585 fm.setOutPort(actionOutputPort);
586 }
587
588 //
589 // TODO: Set the following flag
590 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
591 // See method ForwardingBase::pushRoute()
592 //
593
594 //
595 // Write the message to the switch
596 //
597 log.debug("MEASUREMENT: Installing flow entry " + userState +
598 " into switch DPID: " +
599 sw.getStringId() +
600 " flowEntryId: " + flowEntryId.toString() +
601 " srcMac: " + matchSrcMac + " dstMac: " + matchDstMac +
602 " inPort: " + matchInPort + " outPort: " + actionOutputPort
603 );
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800604 add(sw,fm);
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800605 //
606 // TODO: We should use the OpenFlow Barrier mechanism
607 // to check for errors, and update the SwitchState
608 // for a flow entry after the Barrier message is
609 // is received.
610 //
611 flowEntryObj.setSwitchState("FE_SWITCH_UPDATED");
612
613 return true;
614 }
615
Naoki Shiota2e2fc2b2013-11-12 11:21:36 -0800616 public boolean add(IOFSwitch sw, FlowPath flowPath, FlowEntry flowEntry) {
617 //
618 // Create the OpenFlow Flow Modification Entry to push
619 //
620 OFFlowMod fm = (OFFlowMod) factory.getMessage(OFType.FLOW_MOD);
621 long cookie = flowEntry.flowEntryId().value();
622
623 short flowModCommand = OFFlowMod.OFPFC_ADD;
624 if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_ADD) {
625 flowModCommand = OFFlowMod.OFPFC_ADD;
626 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_MODIFY) {
627 flowModCommand = OFFlowMod.OFPFC_MODIFY_STRICT;
628 } else if (flowEntry.flowEntryUserState() == FlowEntryUserState.FE_USER_DELETE) {
629 flowModCommand = OFFlowMod.OFPFC_DELETE_STRICT;
630 } else {
631 // Unknown user state. Ignore the entry
632 log.debug(
633 "Flow Entry ignored (FlowEntryId = {}): unknown user state {}",
634 flowEntry.flowEntryId().toString(),
635 flowEntry.flowEntryUserState());
636 return false;
637 }
638
639 //
640 // Fetch the match conditions.
641 //
642 // NOTE: The Flow matching conditions common for all Flow Entries are
643 // used ONLY if a Flow Entry does NOT have the corresponding matching
644 // condition set.
645 //
646 OFMatch match = new OFMatch();
647 match.setWildcards(OFMatch.OFPFW_ALL);
648 FlowEntryMatch flowPathMatch = flowPath.flowEntryMatch();
649 FlowEntryMatch flowEntryMatch = flowEntry.flowEntryMatch();
650
651 // Match the Incoming Port
652 Port matchInPort = flowEntryMatch.inPort();
653 if (matchInPort != null) {
654 match.setInputPort(matchInPort.value());
655 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_IN_PORT);
656 }
657
658 // Match the Source MAC address
659 MACAddress matchSrcMac = flowEntryMatch.srcMac();
660 if ((matchSrcMac == null) && (flowPathMatch != null)) {
661 matchSrcMac = flowPathMatch.srcMac();
662 }
663 if (matchSrcMac != null) {
664 match.setDataLayerSource(matchSrcMac.toString());
665 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_SRC);
666 }
667
668 // Match the Destination MAC address
669 MACAddress matchDstMac = flowEntryMatch.dstMac();
670 if ((matchDstMac == null) && (flowPathMatch != null)) {
671 matchDstMac = flowPathMatch.dstMac();
672 }
673 if (matchDstMac != null) {
674 match.setDataLayerDestination(matchDstMac.toString());
675 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_DST);
676 }
677
678 // Match the Ethernet Frame Type
679 Short matchEthernetFrameType = flowEntryMatch.ethernetFrameType();
680 if ((matchEthernetFrameType == null) && (flowPathMatch != null)) {
681 matchEthernetFrameType = flowPathMatch.ethernetFrameType();
682 }
683 if (matchEthernetFrameType != null) {
684 match.setDataLayerType(matchEthernetFrameType);
685 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_TYPE);
686 }
687
688 // Match the VLAN ID
689 Short matchVlanId = flowEntryMatch.vlanId();
690 if ((matchVlanId == null) && (flowPathMatch != null)) {
691 matchVlanId = flowPathMatch.vlanId();
692 }
693 if (matchVlanId != null) {
694 match.setDataLayerVirtualLan(matchVlanId);
695 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_DL_VLAN);
696 }
697
698 // Match the VLAN priority
699 Byte matchVlanPriority = flowEntryMatch.vlanPriority();
700 if ((matchVlanPriority == null) && (flowPathMatch != null)) {
701 matchVlanPriority = flowPathMatch.vlanPriority();
702 }
703 if (matchVlanPriority != null) {
704 match.setDataLayerVirtualLanPriorityCodePoint(matchVlanPriority);
705 match.setWildcards(match.getWildcards()
706 & ~OFMatch.OFPFW_DL_VLAN_PCP);
707 }
708
709 // Match the Source IPv4 Network prefix
710 IPv4Net matchSrcIPv4Net = flowEntryMatch.srcIPv4Net();
711 if ((matchSrcIPv4Net == null) && (flowPathMatch != null)) {
712 matchSrcIPv4Net = flowPathMatch.srcIPv4Net();
713 }
714 if (matchSrcIPv4Net != null) {
715 match.setFromCIDR(matchSrcIPv4Net.toString(), OFMatch.STR_NW_SRC);
716 }
717
718 // Natch the Destination IPv4 Network prefix
719 IPv4Net matchDstIPv4Net = flowEntryMatch.dstIPv4Net();
720 if ((matchDstIPv4Net == null) && (flowPathMatch != null)) {
721 matchDstIPv4Net = flowPathMatch.dstIPv4Net();
722 }
723 if (matchDstIPv4Net != null) {
724 match.setFromCIDR(matchDstIPv4Net.toString(), OFMatch.STR_NW_DST);
725 }
726
727 // Match the IP protocol
728 Byte matchIpProto = flowEntryMatch.ipProto();
729 if ((matchIpProto == null) && (flowPathMatch != null)) {
730 matchIpProto = flowPathMatch.ipProto();
731 }
732 if (matchIpProto != null) {
733 match.setNetworkProtocol(matchIpProto);
734 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_PROTO);
735 }
736
737 // Match the IP ToS (DSCP field, 6 bits)
738 Byte matchIpToS = flowEntryMatch.ipToS();
739 if ((matchIpToS == null) && (flowPathMatch != null)) {
740 matchIpToS = flowPathMatch.ipToS();
741 }
742 if (matchIpToS != null) {
743 match.setNetworkTypeOfService(matchIpToS);
744 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_NW_TOS);
745 }
746
747 // Match the Source TCP/UDP port
748 Short matchSrcTcpUdpPort = flowEntryMatch.srcTcpUdpPort();
749 if ((matchSrcTcpUdpPort == null) && (flowPathMatch != null)) {
750 matchSrcTcpUdpPort = flowPathMatch.srcTcpUdpPort();
751 }
752 if (matchSrcTcpUdpPort != null) {
753 match.setTransportSource(matchSrcTcpUdpPort);
754 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_SRC);
755 }
756
757 // Match the Destination TCP/UDP port
758 Short matchDstTcpUdpPort = flowEntryMatch.dstTcpUdpPort();
759 if ((matchDstTcpUdpPort == null) && (flowPathMatch != null)) {
760 matchDstTcpUdpPort = flowPathMatch.dstTcpUdpPort();
761 }
762 if (matchDstTcpUdpPort != null) {
763 match.setTransportDestination(matchDstTcpUdpPort);
764 match.setWildcards(match.getWildcards() & ~OFMatch.OFPFW_TP_DST);
765 }
766
767 //
768 // Fetch the actions
769 //
770 Short actionOutputPort = null;
771 List<OFAction> openFlowActions = new ArrayList<OFAction>();
772 int actionsLen = 0;
773 FlowEntryActions flowEntryActions = flowEntry.flowEntryActions();
774 //
775 for (FlowEntryAction action : flowEntryActions.actions()) {
776 ActionOutput actionOutput = action.actionOutput();
777 ActionSetVlanId actionSetVlanId = action.actionSetVlanId();
778 ActionSetVlanPriority actionSetVlanPriority = action
779 .actionSetVlanPriority();
780 ActionStripVlan actionStripVlan = action.actionStripVlan();
781 ActionSetEthernetAddr actionSetEthernetSrcAddr = action
782 .actionSetEthernetSrcAddr();
783 ActionSetEthernetAddr actionSetEthernetDstAddr = action
784 .actionSetEthernetDstAddr();
785 ActionSetIPv4Addr actionSetIPv4SrcAddr = action
786 .actionSetIPv4SrcAddr();
787 ActionSetIPv4Addr actionSetIPv4DstAddr = action
788 .actionSetIPv4DstAddr();
789 ActionSetIpToS actionSetIpToS = action.actionSetIpToS();
790 ActionSetTcpUdpPort actionSetTcpUdpSrcPort = action
791 .actionSetTcpUdpSrcPort();
792 ActionSetTcpUdpPort actionSetTcpUdpDstPort = action
793 .actionSetTcpUdpDstPort();
794 ActionEnqueue actionEnqueue = action.actionEnqueue();
795
796 if (actionOutput != null) {
797 actionOutputPort = actionOutput.port().value();
798 // XXX: The max length is hard-coded for now
799 OFActionOutput ofa = new OFActionOutput(actionOutput.port()
800 .value(), (short) 0xffff);
801 openFlowActions.add(ofa);
802 actionsLen += ofa.getLength();
803 }
804
805 if (actionSetVlanId != null) {
806 OFActionVirtualLanIdentifier ofa = new OFActionVirtualLanIdentifier(
807 actionSetVlanId.vlanId());
808 openFlowActions.add(ofa);
809 actionsLen += ofa.getLength();
810 }
811
812 if (actionSetVlanPriority != null) {
813 OFActionVirtualLanPriorityCodePoint ofa = new OFActionVirtualLanPriorityCodePoint(
814 actionSetVlanPriority.vlanPriority());
815 openFlowActions.add(ofa);
816 actionsLen += ofa.getLength();
817 }
818
819 if (actionStripVlan != null) {
820 if (actionStripVlan.stripVlan() == true) {
821 OFActionStripVirtualLan ofa = new OFActionStripVirtualLan();
822 openFlowActions.add(ofa);
823 actionsLen += ofa.getLength();
824 }
825 }
826
827 if (actionSetEthernetSrcAddr != null) {
828 OFActionDataLayerSource ofa = new OFActionDataLayerSource(
829 actionSetEthernetSrcAddr.addr().toBytes());
830 openFlowActions.add(ofa);
831 actionsLen += ofa.getLength();
832 }
833
834 if (actionSetEthernetDstAddr != null) {
835 OFActionDataLayerDestination ofa = new OFActionDataLayerDestination(
836 actionSetEthernetDstAddr.addr().toBytes());
837 openFlowActions.add(ofa);
838 actionsLen += ofa.getLength();
839 }
840
841 if (actionSetIPv4SrcAddr != null) {
842 OFActionNetworkLayerSource ofa = new OFActionNetworkLayerSource(
843 actionSetIPv4SrcAddr.addr().value());
844 openFlowActions.add(ofa);
845 actionsLen += ofa.getLength();
846 }
847
848 if (actionSetIPv4DstAddr != null) {
849 OFActionNetworkLayerDestination ofa = new OFActionNetworkLayerDestination(
850 actionSetIPv4DstAddr.addr().value());
851 openFlowActions.add(ofa);
852 actionsLen += ofa.getLength();
853 }
854
855 if (actionSetIpToS != null) {
856 OFActionNetworkTypeOfService ofa = new OFActionNetworkTypeOfService(
857 actionSetIpToS.ipToS());
858 openFlowActions.add(ofa);
859 actionsLen += ofa.getLength();
860 }
861
862 if (actionSetTcpUdpSrcPort != null) {
863 OFActionTransportLayerSource ofa = new OFActionTransportLayerSource(
864 actionSetTcpUdpSrcPort.port());
865 openFlowActions.add(ofa);
866 actionsLen += ofa.getLength();
867 }
868
869 if (actionSetTcpUdpDstPort != null) {
870 OFActionTransportLayerDestination ofa = new OFActionTransportLayerDestination(
871 actionSetTcpUdpDstPort.port());
872 openFlowActions.add(ofa);
873 actionsLen += ofa.getLength();
874 }
875
876 if (actionEnqueue != null) {
877 OFActionEnqueue ofa = new OFActionEnqueue(actionEnqueue.port()
878 .value(), actionEnqueue.queueId());
879 openFlowActions.add(ofa);
880 actionsLen += ofa.getLength();
881 }
882 }
883
884 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
885 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
886 .setPriority(PRIORITY_DEFAULT)
887 .setBufferId(OFPacketOut.BUFFER_ID_NONE).setCookie(cookie)
888 .setCommand(flowModCommand).setMatch(match)
889 .setActions(openFlowActions)
890 .setLengthU(OFFlowMod.MINIMUM_LENGTH + actionsLen);
891 fm.setOutPort(OFPort.OFPP_NONE.getValue());
892 if ((flowModCommand == OFFlowMod.OFPFC_DELETE)
893 || (flowModCommand == OFFlowMod.OFPFC_DELETE_STRICT)) {
894 if (actionOutputPort != null)
895 fm.setOutPort(actionOutputPort);
896 }
897
898 //
899 // TODO: Set the following flag
900 // fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
901 // See method ForwardingBase::pushRoute()
902 //
903
904 //
905 // Write the message to the switch
906 //
907 log.debug("MEASUREMENT: Installing flow entry "
908 + flowEntry.flowEntryUserState() + " into switch DPID: "
909 + sw.getStringId() + " flowEntryId: "
910 + flowEntry.flowEntryId().toString() + " srcMac: "
911 + matchSrcMac + " dstMac: " + matchDstMac + " inPort: "
912 + matchInPort + " outPort: " + actionOutputPort);
913
914 //
915 // TODO: We should use the OpenFlow Barrier mechanism
916 // to check for errors, and update the SwitchState
917 // for a flow entry after the Barrier message is
918 // is received.
919 //
920 // TODO: The FlowEntry Object in Titan should be set
921 // to FE_SWITCH_UPDATED.
922 //
923
924 return add(sw,fm);
925 }
926
Naoki Shiota7d0cf272013-11-05 10:18:12 -0800927 private SwitchQueue getQueue(IOFSwitch sw) {
928 if (sw == null) {
929 return null;
930 }
931
932 return queues.get(sw);
933 }
Naoki Shiotaed4eb5e2013-10-31 10:55:32 -0700934}