blob: 5faf38e097aa25783216f98bc43ba5b2e63ee180 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/*
2 * Copyright Big Switch Networks 2012
3 */
4
5package net.floodlightcontroller.util;
6
7import java.io.IOException;
8import java.util.EnumSet;
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -07009import java.util.Iterator;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080010import java.util.Set;
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070011import java.util.concurrent.ExecutorService;
12import java.util.concurrent.Executors;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080013
14import net.floodlightcontroller.core.FloodlightContext;
15import net.floodlightcontroller.core.IOFSwitch;
16
17import org.openflow.protocol.OFMessage;
18import org.openflow.protocol.OFType;
19
20/**
Ray Milkey269ffb92014-04-03 14:43:30 -070021 * Dampens OFMessages sent to an OF switch. A message is only written to
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080022 * a switch if the same message (as defined by .equals()) has not been written
23 * in the last n milliseconds. Timer granularity is based on TimedCache
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080024 *
Ray Milkey269ffb92014-04-03 14:43:30 -070025 * @author gregor
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080026 */
27public class OFMessageDamper {
28 /**
29 * An entry in the TimedCache. A cache entry consists of the sent message
Ray Milkey269ffb92014-04-03 14:43:30 -070030 * as well as the switch to which the message was sent.
31 * <p/>
32 * NOTE: We currently use the full OFMessage object. To save space, we
33 * could use a cryptographic hash (e.g., SHA-1). However, this would
34 * obviously be more time-consuming....
35 * <p/>
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080036 * We also store a reference to the actual IOFSwitch object and /not/
37 * the switch DPID. This way we are guarnteed to not dampen messages if
38 * a switch disconnects and then reconnects.
Ray Milkey269ffb92014-04-03 14:43:30 -070039 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080040 * @author gregor
41 */
42 protected static class DamperEntry {
43 OFMessage msg;
44 IOFSwitch sw;
Ray Milkey269ffb92014-04-03 14:43:30 -070045
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080046 public DamperEntry(OFMessage msg, IOFSwitch sw) {
47 super();
48 this.msg = msg;
49 this.sw = sw;
50 }
Ray Milkey269ffb92014-04-03 14:43:30 -070051
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080052 /* (non-Javadoc)
53 * @see java.lang.Object#hashCode()
54 */
55 @Override
56 public int hashCode() {
57 final int prime = 31;
58 int result = 1;
59 result = prime * result + ((msg == null) ? 0 : msg.hashCode());
60 result = prime * result + ((sw == null) ? 0 : sw.hashCode());
61 return result;
62 }
Ray Milkey269ffb92014-04-03 14:43:30 -070063
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080064 /* (non-Javadoc)
65 * @see java.lang.Object#equals(java.lang.Object)
66 */
67 @Override
68 public boolean equals(Object obj) {
69 if (this == obj) return true;
70 if (obj == null) return false;
71 if (getClass() != obj.getClass()) return false;
72 DamperEntry other = (DamperEntry) obj;
73 if (msg == null) {
74 if (other.msg != null) return false;
75 } else if (!msg.equals(other.msg)) return false;
76 if (sw == null) {
77 if (other.sw != null) return false;
78 } else if (!sw.equals(other.sw)) return false;
79 return true;
80 }
Ray Milkey269ffb92014-04-03 14:43:30 -070081
82
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080083 }
Ray Milkey269ffb92014-04-03 14:43:30 -070084
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080085 TimedCache<DamperEntry> cache;
86 EnumSet<OFType> msgTypesToCache;
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -070087 // executor for invalidate task
88 private static ExecutorService executor = Executors.newFixedThreadPool(1);
Ray Milkey269ffb92014-04-03 14:43:30 -070089
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080090 /**
Ray Milkey269ffb92014-04-03 14:43:30 -070091 * @param capacity the maximum number of messages that should be
92 * kept
93 * @param typesToDampen The set of OFMessageTypes that should be
94 * dampened by this instance. Other types will be passed through
95 * @param timeout The dampening timeout. A message will only be
96 * written if the last write for the an equal message more than
97 * timeout ms ago.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080098 */
Ray Milkey269ffb92014-04-03 14:43:30 -070099 public OFMessageDamper(int capacity,
100 Set<OFType> typesToDampen,
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800101 int timeout) {
102 cache = new TimedCache<DamperEntry>(capacity, timeout);
103 msgTypesToCache = EnumSet.copyOf(typesToDampen);
Ray Milkey269ffb92014-04-03 14:43:30 -0700104 }
105
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800106 /**
107 * write the messag to the switch according to our dampening settings
Ray Milkey269ffb92014-04-03 14:43:30 -0700108 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800109 * @param sw
110 * @param msg
111 * @param cntx
112 * @return true if the message was written to the switch, false if
Ray Milkey269ffb92014-04-03 14:43:30 -0700113 * the message was dampened.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800114 * @throws IOException
115 */
116 public boolean write(IOFSwitch sw, OFMessage msg, FloodlightContext cntx)
Ray Milkey269ffb92014-04-03 14:43:30 -0700117 throws IOException {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800118 return write(sw, msg, cntx, false);
119 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700120
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800121 /**
122 * write the messag to the switch according to our dampening settings
Ray Milkey269ffb92014-04-03 14:43:30 -0700123 *
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800124 * @param sw
125 * @param msg
126 * @param cntx
127 * @param flush true to flush the packet immidiately
128 * @return true if the message was written to the switch, false if
Ray Milkey269ffb92014-04-03 14:43:30 -0700129 * the message was dampened.
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800130 * @throws IOException
131 */
132 public boolean write(IOFSwitch sw, OFMessage msg,
Ray Milkey269ffb92014-04-03 14:43:30 -0700133 FloodlightContext cntx, boolean flush)
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800134 throws IOException {
Ray Milkey269ffb92014-04-03 14:43:30 -0700135 if (!msgTypesToCache.contains(msg.getType())) {
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800136 sw.write(msg, cntx);
137 if (flush) {
138 sw.flush();
139 }
140 return true;
141 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700142
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800143 DamperEntry entry = new DamperEntry(msg, sw);
144 if (cache.update(entry)) {
145 // entry exists in cache. Dampening.
Ray Milkey269ffb92014-04-03 14:43:30 -0700146 return false;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800147 } else {
148 sw.write(msg, cntx);
149 if (flush) {
150 sw.flush();
151 }
152 return true;
153 }
154 }
Yuta HIGUCHIafadeda2014-07-24 17:11:07 -0700155
156 /**
157 * Invalidates all the damper cache entries for the specified switch.
158 *
159 * @param sw switch connection to invalidate
160 */
161 public void invalidate(final IOFSwitch sw) {
162 executor.submit(new Runnable() {
163 @Override
164 public void run() {
165 Iterator<DamperEntry> it = cache.getCachedEntries().iterator();
166 while (it.hasNext()) {
167 DamperEntry entry = it.next();
168 if (entry.sw == sw) {
169 it.remove();
170 }
171 }
172 }
173 });
174 }
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -0800175}