Ayaka Koshibe

Tests for FlowRuleStore plus bugfixes

Change-Id: Ib5b0bd9d41fbbcac1cf09684e70446326887caf7
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;
......
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++) {
......