| /* |
| * Copyright Big Switch Networks 2012 |
| */ |
| |
| package net.floodlightcontroller.util; |
| |
| import java.io.IOException; |
| import java.util.EnumSet; |
| import java.util.Set; |
| |
| import net.floodlightcontroller.core.FloodlightContext; |
| import net.floodlightcontroller.core.IOFSwitch; |
| |
| import org.openflow.protocol.OFMessage; |
| import org.openflow.protocol.OFType; |
| |
| /** |
| * Dampens OFMessages sent to an OF switch. A message is only written to |
| * a switch if the same message (as defined by .equals()) has not been written |
| * in the last n milliseconds. Timer granularity is based on TimedCache |
| * @author gregor |
| * |
| */ |
| public class OFMessageDamper { |
| /** |
| * An entry in the TimedCache. A cache entry consists of the sent message |
| * as well as the switch to which the message was sent. |
| * |
| * NOTE: We currently use the full OFMessage object. To save space, we |
| * could use a cryptographic hash (e.g., SHA-1). However, this would |
| * obviously be more time-consuming.... |
| * |
| * We also store a reference to the actual IOFSwitch object and /not/ |
| * the switch DPID. This way we are guarnteed to not dampen messages if |
| * a switch disconnects and then reconnects. |
| * |
| * @author gregor |
| */ |
| protected static class DamperEntry { |
| OFMessage msg; |
| IOFSwitch sw; |
| public DamperEntry(OFMessage msg, IOFSwitch sw) { |
| super(); |
| this.msg = msg; |
| this.sw = sw; |
| } |
| /* (non-Javadoc) |
| * @see java.lang.Object#hashCode() |
| */ |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((msg == null) ? 0 : msg.hashCode()); |
| result = prime * result + ((sw == null) ? 0 : sw.hashCode()); |
| return result; |
| } |
| /* (non-Javadoc) |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) return true; |
| if (obj == null) return false; |
| if (getClass() != obj.getClass()) return false; |
| DamperEntry other = (DamperEntry) obj; |
| if (msg == null) { |
| if (other.msg != null) return false; |
| } else if (!msg.equals(other.msg)) return false; |
| if (sw == null) { |
| if (other.sw != null) return false; |
| } else if (!sw.equals(other.sw)) return false; |
| return true; |
| } |
| |
| |
| } |
| TimedCache<DamperEntry> cache; |
| EnumSet<OFType> msgTypesToCache; |
| /** |
| * |
| * @param capacity the maximum number of messages that should be |
| * kept |
| * @param typesToDampen The set of OFMessageTypes that should be |
| * dampened by this instance. Other types will be passed through |
| * @param timeout The dampening timeout. A message will only be |
| * written if the last write for the an equal message more than |
| * timeout ms ago. |
| */ |
| public OFMessageDamper(int capacity, |
| Set<OFType> typesToDampen, |
| int timeout) { |
| cache = new TimedCache<DamperEntry>(capacity, timeout); |
| msgTypesToCache = EnumSet.copyOf(typesToDampen); |
| } |
| |
| /** |
| * write the messag to the switch according to our dampening settings |
| * @param sw |
| * @param msg |
| * @param cntx |
| * @return true if the message was written to the switch, false if |
| * the message was dampened. |
| * @throws IOException |
| */ |
| public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) |
| throws IOException { |
| return write(sw, msg, cntx, false); |
| } |
| |
| /** |
| * write the messag to the switch according to our dampening settings |
| * @param sw |
| * @param msg |
| * @param cntx |
| * @param flush true to flush the packet immidiately |
| * @return true if the message was written to the switch, false if |
| * the message was dampened. |
| * @throws IOException |
| */ |
| public boolean write(IOFSwitch sw, OFMessage msg, |
| FloodlightContext cntx, boolean flush) |
| throws IOException { |
| if (! msgTypesToCache.contains(msg.getType())) { |
| sw.write(msg, cntx); |
| if (flush) { |
| sw.flush(); |
| } |
| return true; |
| } |
| |
| DamperEntry entry = new DamperEntry(msg, sw); |
| if (cache.update(entry)) { |
| // entry exists in cache. Dampening. |
| return false; |
| } else { |
| sw.write(msg, cntx); |
| if (flush) { |
| sw.flush(); |
| } |
| return true; |
| } |
| } |
| } |