Showing
6 changed files
with
362 additions
and
13 deletions
1 | package org.onlab.onos.net.flow; | 1 | package org.onlab.onos.net.flow; |
2 | 2 | ||
3 | +import static com.google.common.base.MoreObjects.toStringHelper; | ||
4 | + | ||
3 | import org.onlab.onos.net.DeviceId; | 5 | import org.onlab.onos.net.DeviceId; |
4 | 6 | ||
5 | public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { | 7 | public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { |
... | @@ -63,7 +65,9 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { | ... | @@ -63,7 +65,9 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { |
63 | public int hashCode() { | 65 | public int hashCode() { |
64 | final int prime = 31; | 66 | final int prime = 31; |
65 | int result = prime * this.deviceId().hashCode(); | 67 | int result = prime * this.deviceId().hashCode(); |
66 | - result = prime * result + Long.valueOf(this.created).hashCode(); | 68 | + result = prime * result + this.priority; |
69 | + result = prime * result + this.selector().hashCode(); | ||
70 | + result = prime * result + this.treatment().hashCode(); | ||
67 | return result; | 71 | return result; |
68 | } | 72 | } |
69 | 73 | ||
... | @@ -77,7 +81,10 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { | ... | @@ -77,7 +81,10 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { |
77 | public boolean equals(Object obj) { | 81 | public boolean equals(Object obj) { |
78 | if (obj instanceof DefaultFlowEntry) { | 82 | if (obj instanceof DefaultFlowEntry) { |
79 | DefaultFlowEntry that = (DefaultFlowEntry) obj; | 83 | DefaultFlowEntry that = (DefaultFlowEntry) obj; |
80 | - if (!this.id.equals(that.id())) { | 84 | + if (!this.deviceId().equals(that.deviceId())) { |
85 | + return false; | ||
86 | + } | ||
87 | + if (!(this.priority == that.priority)) { | ||
81 | return false; | 88 | return false; |
82 | } | 89 | } |
83 | return super.equals(obj); | 90 | return super.equals(obj); |
... | @@ -85,4 +92,15 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { | ... | @@ -85,4 +92,15 @@ public class DefaultFlowEntry extends DefaultFlowRule implements FlowEntry { |
85 | return false; | 92 | return false; |
86 | } | 93 | } |
87 | 94 | ||
95 | + @Override | ||
96 | + public String toString() { | ||
97 | + return toStringHelper(this) | ||
98 | + .add("id", id) | ||
99 | + .add("deviceId", deviceId()) | ||
100 | + .add("priority", priority) | ||
101 | + .add("selector", selector()) | ||
102 | + .add("treatment", treatment()) | ||
103 | + .toString(); | ||
104 | + } | ||
105 | + | ||
88 | } | 106 | } | ... | ... |
... | @@ -17,6 +17,7 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -17,6 +17,7 @@ public class DefaultFlowRule implements FlowRule { |
17 | 17 | ||
18 | @Override | 18 | @Override |
19 | public int priority() { | 19 | public int priority() { |
20 | + // is this supposed to be 0? | ||
20 | return 0; | 21 | return 0; |
21 | } | 22 | } |
22 | 23 | ||
... | @@ -63,8 +64,9 @@ public class DefaultFlowRule implements FlowRule { | ... | @@ -63,8 +64,9 @@ public class DefaultFlowRule implements FlowRule { |
63 | if (!this.selector().equals(that.selector())) { | 64 | if (!this.selector().equals(that.selector())) { |
64 | return false; | 65 | return false; |
65 | } | 66 | } |
67 | + return true; | ||
66 | } | 68 | } |
67 | - return true; | 69 | + return false; |
68 | } | 70 | } |
69 | 71 | ||
70 | 72 | ... | ... |
... | @@ -45,10 +45,10 @@ implements FlowRuleService, FlowRuleProviderRegistry { | ... | @@ -45,10 +45,10 @@ implements FlowRuleService, FlowRuleProviderRegistry { |
45 | private final SimpleFlowRuleStore store = new SimpleFlowRuleStore(); | 45 | private final SimpleFlowRuleStore store = new SimpleFlowRuleStore(); |
46 | 46 | ||
47 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 47 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
48 | - private EventDeliveryService eventDispatcher; | 48 | + protected EventDeliveryService eventDispatcher; |
49 | 49 | ||
50 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 50 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
51 | - private DeviceService deviceService; | 51 | + protected DeviceService deviceService; |
52 | 52 | ||
53 | @Activate | 53 | @Activate |
54 | public void activate() { | 54 | public void activate() { | ... | ... |
... | @@ -53,17 +53,20 @@ public class SimpleFlowRuleStore { | ... | @@ -53,17 +53,20 @@ public class SimpleFlowRuleStore { |
53 | FlowRuleEvent addOrUpdateFlowRule(FlowRule rule) { | 53 | FlowRuleEvent addOrUpdateFlowRule(FlowRule rule) { |
54 | DeviceId did = rule.deviceId(); | 54 | DeviceId did = rule.deviceId(); |
55 | 55 | ||
56 | + FlowEntry entry = new DefaultFlowEntry( | ||
57 | + did, | ||
58 | + rule.selector(), | ||
59 | + rule.treatment(), | ||
60 | + rule.priority()); | ||
61 | + | ||
56 | // check if this new rule is an update to an existing entry | 62 | // check if this new rule is an update to an existing entry |
57 | for (FlowEntry fe : flowEntries.get(did)) { | 63 | for (FlowEntry fe : flowEntries.get(did)) { |
58 | - if (rule.equals(fe)) { | 64 | + if (entry.equals(fe)) { |
59 | // TODO update the stats on this flowEntry? | 65 | // TODO update the stats on this flowEntry? |
60 | return null; | 66 | return null; |
61 | } | 67 | } |
62 | } | 68 | } |
63 | - | 69 | + flowEntries.put(did, entry); |
64 | - FlowEntry newfe = new DefaultFlowEntry(did, | ||
65 | - rule.selector(), rule.treatment(), rule.priority()); | ||
66 | - flowEntries.put(did, newfe); | ||
67 | return new FlowRuleEvent(RULE_ADDED, rule); | 70 | return new FlowRuleEvent(RULE_ADDED, rule); |
68 | } | 71 | } |
69 | 72 | ||
... | @@ -73,8 +76,11 @@ public class SimpleFlowRuleStore { | ... | @@ -73,8 +76,11 @@ public class SimpleFlowRuleStore { |
73 | * @return flow_removed event, or null if nothing removed | 76 | * @return flow_removed event, or null if nothing removed |
74 | */ | 77 | */ |
75 | FlowRuleEvent removeFlowRule(FlowRule rule) { | 78 | FlowRuleEvent removeFlowRule(FlowRule rule) { |
79 | + | ||
80 | + FlowEntry rem = new DefaultFlowEntry(rule.deviceId(), | ||
81 | + rule.selector(), rule.treatment(), rule.priority()); | ||
76 | synchronized (this) { | 82 | synchronized (this) { |
77 | - if (flowEntries.remove(rule.deviceId(), rule)) { | 83 | + if (flowEntries.remove(rem.deviceId(), rem)) { |
78 | return new FlowRuleEvent(RULE_REMOVED, rule); | 84 | return new FlowRuleEvent(RULE_REMOVED, rule); |
79 | } else { | 85 | } else { |
80 | return null; | 86 | return null; | ... | ... |
core/trivial/src/test/java/org/onlab/onos/net/trivial/flow/impl/SimpleFlowRuleManagerTest.java
0 → 100644
1 | +package org.onlab.onos.net.trivial.flow.impl; | ||
2 | + | ||
3 | +import static org.junit.Assert.assertEquals; | ||
4 | +import static org.junit.Assert.assertFalse; | ||
5 | +import static org.junit.Assert.assertNotNull; | ||
6 | +import static org.junit.Assert.assertTrue; | ||
7 | + | ||
8 | +import java.util.ArrayList; | ||
9 | +import java.util.List; | ||
10 | + | ||
11 | +import org.junit.After; | ||
12 | +import org.junit.Before; | ||
13 | +import org.junit.Test; | ||
14 | +import org.onlab.onos.event.impl.TestEventDispatcher; | ||
15 | +import org.onlab.onos.net.DefaultDevice; | ||
16 | +import org.onlab.onos.net.Device; | ||
17 | +import org.onlab.onos.net.Device.Type; | ||
18 | +import org.onlab.onos.net.DeviceId; | ||
19 | +import org.onlab.onos.net.MastershipRole; | ||
20 | +import org.onlab.onos.net.Port; | ||
21 | +import org.onlab.onos.net.PortNumber; | ||
22 | +import org.onlab.onos.net.device.DeviceListener; | ||
23 | +import org.onlab.onos.net.device.DeviceService; | ||
24 | +import org.onlab.onos.net.flow.DefaultFlowEntry; | ||
25 | +import org.onlab.onos.net.flow.DefaultFlowRule; | ||
26 | +import org.onlab.onos.net.flow.FlowEntry; | ||
27 | +import org.onlab.onos.net.flow.FlowRule; | ||
28 | +import org.onlab.onos.net.flow.FlowRuleEvent; | ||
29 | +import org.onlab.onos.net.flow.FlowRuleListener; | ||
30 | +import org.onlab.onos.net.flow.FlowRuleProvider; | ||
31 | +import org.onlab.onos.net.flow.FlowRuleProviderRegistry; | ||
32 | +import org.onlab.onos.net.flow.FlowRuleProviderService; | ||
33 | +import org.onlab.onos.net.flow.FlowRuleService; | ||
34 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
35 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
36 | +import org.onlab.onos.net.flow.criteria.Criterion; | ||
37 | +import org.onlab.onos.net.flow.instructions.Instruction; | ||
38 | +import org.onlab.onos.net.provider.AbstractProvider; | ||
39 | +import org.onlab.onos.net.provider.ProviderId; | ||
40 | + | ||
41 | +import com.google.common.collect.Lists; | ||
42 | +import com.google.common.collect.Sets; | ||
43 | + | ||
44 | +import static org.onlab.onos.net.flow.FlowRuleEvent.Type.*; | ||
45 | + | ||
46 | +/** | ||
47 | + * Test codifying the flow rule service & flow rule provider service contracts. | ||
48 | + */ | ||
49 | +public class SimpleFlowRuleManagerTest { | ||
50 | + | ||
51 | + private static final ProviderId PID = new ProviderId("foo"); | ||
52 | + private static final DeviceId DID = DeviceId.deviceId("of:001"); | ||
53 | + private static final Device DEV = new DefaultDevice( | ||
54 | + PID, DID, Type.SWITCH, "", "", "", ""); | ||
55 | + | ||
56 | + private SimpleFlowRuleManager mgr; | ||
57 | + | ||
58 | + protected FlowRuleService service; | ||
59 | + protected FlowRuleProviderRegistry registry; | ||
60 | + protected FlowRuleProviderService providerSerivce; | ||
61 | + protected TestProvider provider; | ||
62 | + protected TestListener listener = new TestListener(); | ||
63 | + | ||
64 | + @Before | ||
65 | + public void setUp() { | ||
66 | + mgr = new SimpleFlowRuleManager(); | ||
67 | + mgr.eventDispatcher = new TestEventDispatcher(); | ||
68 | + mgr.deviceService = new TestDeviceService(); | ||
69 | + service = mgr; | ||
70 | + registry = mgr; | ||
71 | + | ||
72 | + mgr.activate(); | ||
73 | + mgr.addListener(listener); | ||
74 | + provider = new TestProvider(PID); | ||
75 | + providerSerivce = registry.register(provider); | ||
76 | + assertTrue("provider should be registered", | ||
77 | + registry.getProviders().contains(provider.id())); | ||
78 | + } | ||
79 | + | ||
80 | + @After | ||
81 | + public void tearDown() { | ||
82 | + registry.unregister(provider); | ||
83 | + assertFalse("provider should not be registered", | ||
84 | + registry.getProviders().contains(provider.id())); | ||
85 | + service.removeListener(listener); | ||
86 | + mgr.deactivate(); | ||
87 | + mgr.eventDispatcher = null; | ||
88 | + mgr.deviceService = null; | ||
89 | + } | ||
90 | + | ||
91 | + private FlowRule flowRule(int tsval, int trval) { | ||
92 | + TestSelector ts = new TestSelector(tsval); | ||
93 | + TestTreatment tr = new TestTreatment(trval); | ||
94 | + return new DefaultFlowRule(DID, ts, tr); | ||
95 | + } | ||
96 | + | ||
97 | + private void addFlowRule(int hval) { | ||
98 | + FlowRule rule = flowRule(hval, hval); | ||
99 | + providerSerivce.flowAdded(rule); | ||
100 | + assertNotNull("rule should be found", service.getFlowEntries(DID)); | ||
101 | + } | ||
102 | + | ||
103 | + private void validateEvents(FlowRuleEvent.Type ... events) { | ||
104 | + if (events == null) { | ||
105 | + assertTrue("events generated", listener.events.isEmpty()); | ||
106 | + } | ||
107 | + | ||
108 | + int i = 0; | ||
109 | + for (FlowRuleEvent e : listener.events) { | ||
110 | + assertTrue("unexpected event", e.type().equals(events[i])); | ||
111 | + i++; | ||
112 | + } | ||
113 | + | ||
114 | + assertEquals("mispredicted number of events", | ||
115 | + events.length, listener.events.size()); | ||
116 | + | ||
117 | + listener.events.clear(); | ||
118 | + } | ||
119 | + | ||
120 | + private int flowCount() { | ||
121 | + return Sets.newHashSet(service.getFlowEntries(DID)).size(); | ||
122 | + } | ||
123 | + @Test | ||
124 | + public void getFlowEntries() { | ||
125 | + assertTrue("store should be empty", | ||
126 | + Sets.newHashSet(service.getFlowEntries(DID)).isEmpty()); | ||
127 | + addFlowRule(1); | ||
128 | + addFlowRule(2); | ||
129 | + assertEquals("2 rules should exist", 2, flowCount()); | ||
130 | + validateEvents(RULE_ADDED, RULE_ADDED); | ||
131 | + | ||
132 | + addFlowRule(1); | ||
133 | + assertEquals("should still be 2 rules", 2, flowCount()); | ||
134 | + validateEvents(); | ||
135 | + } | ||
136 | + | ||
137 | + @Test | ||
138 | + public void applyFlowRules() { | ||
139 | + TestSelector ts = new TestSelector(1); | ||
140 | + FlowRule r1 = flowRule(1, 1); | ||
141 | + FlowRule r2 = flowRule(1, 2); | ||
142 | + FlowRule r3 = flowRule(1, 3); | ||
143 | + | ||
144 | + //current FlowRules always return 0. FlowEntries inherit the value | ||
145 | + FlowEntry e1 = new DefaultFlowEntry(DID, ts, r1.treatment(), 0); | ||
146 | + FlowEntry e2 = new DefaultFlowEntry(DID, ts, r2.treatment(), 0); | ||
147 | + FlowEntry e3 = new DefaultFlowEntry(DID, ts, r3.treatment(), 0); | ||
148 | + List<FlowEntry> fel = Lists.newArrayList(e1, e2, e3); | ||
149 | + | ||
150 | + assertTrue("store should be empty", | ||
151 | + Sets.newHashSet(service.getFlowEntries(DID)).isEmpty()); | ||
152 | + List<FlowEntry> ret = mgr.applyFlowRules(r1, r2, r3); | ||
153 | + assertEquals("3 rules should exist", 3, flowCount()); | ||
154 | + assertTrue("3 entries should result", fel.containsAll(ret)); | ||
155 | + } | ||
156 | + | ||
157 | + @Test | ||
158 | + public void removeFlowRules() { | ||
159 | + addFlowRule(1); | ||
160 | + addFlowRule(2); | ||
161 | + addFlowRule(3); | ||
162 | + assertEquals("3 rules should exist", 3, flowCount()); | ||
163 | + validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED); | ||
164 | + | ||
165 | + FlowRule rem1 = flowRule(1, 1); | ||
166 | + FlowRule rem2 = flowRule(2, 2); | ||
167 | + mgr.removeFlowRules(rem1, rem2); | ||
168 | + //removing from north, so no events generated | ||
169 | + validateEvents(); | ||
170 | + assertEquals("1 rule should exist", 1, flowCount()); | ||
171 | + | ||
172 | + mgr.removeFlowRules(rem1); | ||
173 | + assertEquals("1 rule should still exist", 1, flowCount()); | ||
174 | + } | ||
175 | + | ||
176 | + @Test | ||
177 | + public void flowRemoved() { | ||
178 | + addFlowRule(1); | ||
179 | + addFlowRule(2); | ||
180 | + FlowRule rem1 = flowRule(1, 1); | ||
181 | + providerSerivce.flowRemoved(rem1); | ||
182 | + validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED); | ||
183 | + | ||
184 | + providerSerivce.flowRemoved(rem1); | ||
185 | + validateEvents(); | ||
186 | + } | ||
187 | + | ||
188 | + private static class TestListener implements FlowRuleListener { | ||
189 | + final List<FlowRuleEvent> events = new ArrayList<>(); | ||
190 | + | ||
191 | + @Override | ||
192 | + public void event(FlowRuleEvent event) { | ||
193 | + events.add(event); | ||
194 | + } | ||
195 | + } | ||
196 | + | ||
197 | + private static class TestDeviceService implements DeviceService { | ||
198 | + | ||
199 | + @Override | ||
200 | + public int getDeviceCount() { | ||
201 | + return 0; | ||
202 | + } | ||
203 | + | ||
204 | + @Override | ||
205 | + public Iterable<Device> getDevices() { | ||
206 | + return null; | ||
207 | + } | ||
208 | + | ||
209 | + @Override | ||
210 | + public Device getDevice(DeviceId deviceId) { | ||
211 | + return DEV; | ||
212 | + } | ||
213 | + | ||
214 | + @Override | ||
215 | + public MastershipRole getRole(DeviceId deviceId) { | ||
216 | + return null; | ||
217 | + } | ||
218 | + | ||
219 | + @Override | ||
220 | + public List<Port> getPorts(DeviceId deviceId) { | ||
221 | + return null; | ||
222 | + } | ||
223 | + | ||
224 | + @Override | ||
225 | + public Port getPort(DeviceId deviceId, PortNumber portNumber) { | ||
226 | + return null; | ||
227 | + } | ||
228 | + | ||
229 | + @Override | ||
230 | + public boolean isAvailable(DeviceId deviceId) { | ||
231 | + return false; | ||
232 | + } | ||
233 | + | ||
234 | + @Override | ||
235 | + public void addListener(DeviceListener listener) { | ||
236 | + } | ||
237 | + | ||
238 | + @Override | ||
239 | + public void removeListener(DeviceListener listener) { | ||
240 | + } | ||
241 | + | ||
242 | + } | ||
243 | + | ||
244 | + private class TestProvider extends AbstractProvider implements FlowRuleProvider { | ||
245 | + | ||
246 | + protected TestProvider(ProviderId id) { | ||
247 | + super(PID); | ||
248 | + } | ||
249 | + | ||
250 | + @Override | ||
251 | + public void applyFlowRule(FlowRule... flowRules) { | ||
252 | + } | ||
253 | + | ||
254 | + @Override | ||
255 | + public void removeFlowRule(FlowRule... flowRules) { | ||
256 | + } | ||
257 | + | ||
258 | + @Override | ||
259 | + public Iterable<FlowEntry> getFlowMetrics(DeviceId deviceId) { | ||
260 | + return null; | ||
261 | + } | ||
262 | + | ||
263 | + } | ||
264 | + | ||
265 | + private class TestSelector implements TrafficSelector { | ||
266 | + | ||
267 | + //for controlling hashcode uniqueness; | ||
268 | + private int testval; | ||
269 | + | ||
270 | + public TestSelector(int val) { | ||
271 | + testval = val; | ||
272 | + } | ||
273 | + | ||
274 | + @Override | ||
275 | + public List<Criterion> criteria() { | ||
276 | + return null; | ||
277 | + } | ||
278 | + | ||
279 | + @Override | ||
280 | + public int hashCode() { | ||
281 | + return testval; | ||
282 | + } | ||
283 | + | ||
284 | + @Override | ||
285 | + public boolean equals(Object o) { | ||
286 | + if (o instanceof TestSelector) { | ||
287 | + return this.testval == ((TestSelector) o).testval; | ||
288 | + } | ||
289 | + return false; | ||
290 | + } | ||
291 | + } | ||
292 | + | ||
293 | + private class TestTreatment implements TrafficTreatment { | ||
294 | + | ||
295 | + //for controlling hashcode uniqueness; | ||
296 | + private int testval; | ||
297 | + | ||
298 | + public TestTreatment(int val) { | ||
299 | + testval = val; | ||
300 | + } | ||
301 | + | ||
302 | + @Override | ||
303 | + public List<Instruction> instructions() { | ||
304 | + return null; | ||
305 | + } | ||
306 | + | ||
307 | + @Override | ||
308 | + public int hashCode() { | ||
309 | + return testval; | ||
310 | + } | ||
311 | + | ||
312 | + @Override | ||
313 | + public boolean equals(Object o) { | ||
314 | + if (o instanceof TestTreatment) { | ||
315 | + return this.testval == ((TestTreatment) o).testval; | ||
316 | + } | ||
317 | + return false; | ||
318 | + } | ||
319 | + | ||
320 | + } | ||
321 | + | ||
322 | +} |
... | @@ -18,6 +18,7 @@ public final class IpAddress { | ... | @@ -18,6 +18,7 @@ public final class IpAddress { |
18 | 18 | ||
19 | //maximum CIDR value | 19 | //maximum CIDR value |
20 | public static final int MAX_INET_MASK = 32; | 20 | public static final int MAX_INET_MASK = 32; |
21 | + //no mask (no network), e.g. a simple address | ||
21 | public static final int DEFAULT_MASK = 0; | 22 | public static final int DEFAULT_MASK = 0; |
22 | 23 | ||
23 | /** | 24 | /** |
... | @@ -112,7 +113,7 @@ public final class IpAddress { | ... | @@ -112,7 +113,7 @@ public final class IpAddress { |
112 | final String [] parts = address.split("\\/"); | 113 | final String [] parts = address.split("\\/"); |
113 | if (parts.length > 2) { | 114 | if (parts.length > 2) { |
114 | throw new IllegalArgumentException("Malformed IP address string; " | 115 | throw new IllegalArgumentException("Malformed IP address string; " |
115 | - + "Addres must take form \"x.x.x.x\" or \"x.x.x.x/y\""); | 116 | + + "Address must take form \"x.x.x.x\" or \"x.x.x.x/y\""); |
116 | } | 117 | } |
117 | 118 | ||
118 | int mask = DEFAULT_MASK; | 119 | int mask = DEFAULT_MASK; |
... | @@ -128,7 +129,7 @@ public final class IpAddress { | ... | @@ -128,7 +129,7 @@ public final class IpAddress { |
128 | final String [] net = parts[0].split("\\."); | 129 | final String [] net = parts[0].split("\\."); |
129 | if (net.length != INET_LEN) { | 130 | if (net.length != INET_LEN) { |
130 | throw new IllegalArgumentException("Malformed IP address string; " | 131 | throw new IllegalArgumentException("Malformed IP address string; " |
131 | - + "Addres must have four decimal values separated by dots (.)"); | 132 | + + "Address must have four decimal values separated by dots (.)"); |
132 | } | 133 | } |
133 | final byte [] bytes = new byte[INET_LEN]; | 134 | final byte [] bytes = new byte[INET_LEN]; |
134 | for (int i = 0; i < INET_LEN; i++) { | 135 | for (int i = 0; i < INET_LEN; i++) { | ... | ... |
-
Please register or login to post a comment