blob: 54abb84ff97d33325b46ad118c2bd2c04cbdef18 [file] [log] [blame]
tombe988312014-09-19 18:38:47 -07001package org.onlab.onos.net.flow.impl;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -07002
3import static org.junit.Assert.assertEquals;
4import static org.junit.Assert.assertFalse;
5import static org.junit.Assert.assertNotNull;
6import static org.junit.Assert.assertTrue;
alshabib97044902014-09-18 14:52:16 -07007import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_ADDED;
8import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
alshabib219ebaa2014-09-22 15:41:24 -07009import static org.onlab.onos.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070010
11import java.util.ArrayList;
12import java.util.List;
13
14import org.junit.After;
15import org.junit.Before;
16import org.junit.Test;
alshabiba68eb962014-09-24 20:34:13 -070017import org.onlab.onos.ApplicationId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070018import org.onlab.onos.event.impl.TestEventDispatcher;
19import org.onlab.onos.net.DefaultDevice;
20import org.onlab.onos.net.Device;
21import org.onlab.onos.net.Device.Type;
22import org.onlab.onos.net.DeviceId;
23import org.onlab.onos.net.MastershipRole;
24import org.onlab.onos.net.Port;
25import org.onlab.onos.net.PortNumber;
26import org.onlab.onos.net.device.DeviceListener;
27import org.onlab.onos.net.device.DeviceService;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070028import org.onlab.onos.net.flow.DefaultFlowRule;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070029import org.onlab.onos.net.flow.FlowRule;
alshabibbb8b1282014-09-22 17:00:18 -070030import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070031import org.onlab.onos.net.flow.FlowRuleEvent;
32import org.onlab.onos.net.flow.FlowRuleListener;
33import org.onlab.onos.net.flow.FlowRuleProvider;
34import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
35import org.onlab.onos.net.flow.FlowRuleProviderService;
36import org.onlab.onos.net.flow.FlowRuleService;
37import org.onlab.onos.net.flow.TrafficSelector;
38import org.onlab.onos.net.flow.TrafficTreatment;
39import org.onlab.onos.net.flow.criteria.Criterion;
40import org.onlab.onos.net.flow.instructions.Instruction;
41import org.onlab.onos.net.provider.AbstractProvider;
42import org.onlab.onos.net.provider.ProviderId;
alshabib219ebaa2014-09-22 15:41:24 -070043import org.onlab.onos.net.trivial.impl.SimpleFlowRuleStore;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070044
45import com.google.common.collect.Lists;
46import com.google.common.collect.Sets;
47
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070048/**
49 * Test codifying the flow rule service & flow rule provider service contracts.
50 */
tom202175a2014-09-19 19:00:11 -070051public class FlowRuleManagerTest {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070052
tomf6ab2152014-09-18 12:08:29 -070053 private static final ProviderId PID = new ProviderId("of", "foo");
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070054 private static final DeviceId DID = DeviceId.deviceId("of:001");
55 private static final Device DEV = new DefaultDevice(
56 PID, DID, Type.SWITCH, "", "", "", "");
57
tom202175a2014-09-19 19:00:11 -070058 private FlowRuleManager mgr;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070059
60 protected FlowRuleService service;
61 protected FlowRuleProviderRegistry registry;
alshabibbb8b1282014-09-22 17:00:18 -070062 protected FlowRuleProviderService providerService;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070063 protected TestProvider provider;
64 protected TestListener listener = new TestListener();
alshabiba68eb962014-09-24 20:34:13 -070065 private ApplicationId appId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070066
67 @Before
68 public void setUp() {
tom202175a2014-09-19 19:00:11 -070069 mgr = new FlowRuleManager();
tombe988312014-09-19 18:38:47 -070070 mgr.store = new SimpleFlowRuleStore();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070071 mgr.eventDispatcher = new TestEventDispatcher();
72 mgr.deviceService = new TestDeviceService();
73 service = mgr;
74 registry = mgr;
75
76 mgr.activate();
77 mgr.addListener(listener);
78 provider = new TestProvider(PID);
alshabibbb8b1282014-09-22 17:00:18 -070079 providerService = registry.register(provider);
alshabiba68eb962014-09-24 20:34:13 -070080 appId = ApplicationId.getAppId();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070081 assertTrue("provider should be registered",
82 registry.getProviders().contains(provider.id()));
83 }
84
85 @After
86 public void tearDown() {
87 registry.unregister(provider);
88 assertFalse("provider should not be registered",
alshabib97044902014-09-18 14:52:16 -070089 registry.getProviders().contains(provider.id()));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070090 service.removeListener(listener);
91 mgr.deactivate();
92 mgr.eventDispatcher = null;
93 mgr.deviceService = null;
94 }
95
96 private FlowRule flowRule(int tsval, int trval) {
97 TestSelector ts = new TestSelector(tsval);
98 TestTreatment tr = new TestTreatment(trval);
alshabiba68eb962014-09-24 20:34:13 -070099 return new DefaultFlowRule(DID, ts, tr, 0, appId);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700100 }
101
alshabibbb8b1282014-09-22 17:00:18 -0700102 private FlowRule flowRule(FlowRule rule, FlowRuleState state) {
103 return new DefaultFlowRule(rule, state);
104 }
105
106 private FlowRule addFlowRule(int hval) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700107 FlowRule rule = flowRule(hval, hval);
alshabibbb8b1282014-09-22 17:00:18 -0700108 providerService.flowAdded(rule);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700109 assertNotNull("rule should be found", service.getFlowEntries(DID));
alshabibbb8b1282014-09-22 17:00:18 -0700110 return rule;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700111 }
112
113 private void validateEvents(FlowRuleEvent.Type ... events) {
114 if (events == null) {
115 assertTrue("events generated", listener.events.isEmpty());
116 }
117
118 int i = 0;
alshabibbb42cad2014-09-25 11:43:05 -0700119 System.err.println("events :" + listener.events);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700120 for (FlowRuleEvent e : listener.events) {
121 assertTrue("unexpected event", e.type().equals(events[i]));
122 i++;
123 }
124
125 assertEquals("mispredicted number of events",
126 events.length, listener.events.size());
127
128 listener.events.clear();
129 }
130
131 private int flowCount() {
132 return Sets.newHashSet(service.getFlowEntries(DID)).size();
133 }
134 @Test
135 public void getFlowEntries() {
136 assertTrue("store should be empty",
137 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
138 addFlowRule(1);
139 addFlowRule(2);
140 assertEquals("2 rules should exist", 2, flowCount());
141 validateEvents(RULE_ADDED, RULE_ADDED);
142
143 addFlowRule(1);
144 assertEquals("should still be 2 rules", 2, flowCount());
alshabib219ebaa2014-09-22 15:41:24 -0700145 validateEvents(RULE_UPDATED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700146 }
147
alshabibbb8b1282014-09-22 17:00:18 -0700148
149 //backing store is sensitive to the order of additions/removals
150 private boolean validateState(FlowRuleState... state) {
151 Iterable<FlowRule> rules = service.getFlowEntries(DID);
152 int i = 0;
153 for (FlowRule f : rules) {
154 if (f.state() != state[i]) {
155 return false;
156 }
157 i++;
158 }
159 return true;
160 }
161
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700162 @Test
163 public void applyFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700164
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700165 FlowRule r1 = flowRule(1, 1);
alshabiba68eb962014-09-24 20:34:13 -0700166 FlowRule r2 = flowRule(2, 2);
167 FlowRule r3 = flowRule(3, 3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700168
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700169 assertTrue("store should be empty",
170 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabib219ebaa2014-09-22 15:41:24 -0700171 mgr.applyFlowRules(r1, r2, r3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700172 assertEquals("3 rules should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700173 assertTrue("Entries should be pending add.",
174 validateState(FlowRuleState.PENDING_ADD, FlowRuleState.PENDING_ADD,
175 FlowRuleState.PENDING_ADD));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700176 }
177
178 @Test
179 public void removeFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700180 FlowRule f1 = addFlowRule(1);
181 FlowRule f2 = addFlowRule(2);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700182 addFlowRule(3);
183 assertEquals("3 rules should exist", 3, flowCount());
184 validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED);
185
alshabibbb8b1282014-09-22 17:00:18 -0700186 FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
187 FlowRule rem2 = flowRule(f2, FlowRuleState.REMOVED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700188 mgr.removeFlowRules(rem1, rem2);
189 //removing from north, so no events generated
190 validateEvents();
alshabib219ebaa2014-09-22 15:41:24 -0700191 assertEquals("3 rule should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700192 assertTrue("Entries should be pending remove.",
193 validateState(FlowRuleState.CREATED, FlowRuleState.PENDING_REMOVE,
194 FlowRuleState.PENDING_REMOVE));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700195
196 mgr.removeFlowRules(rem1);
alshabib219ebaa2014-09-22 15:41:24 -0700197 assertEquals("3 rule should still exist", 3, flowCount());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700198 }
199
200 @Test
201 public void flowRemoved() {
alshabibbb8b1282014-09-22 17:00:18 -0700202 FlowRule f1 = addFlowRule(1);
alshabiba68eb962014-09-24 20:34:13 -0700203 service.removeFlowRules(f1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700204 addFlowRule(2);
alshabibbb8b1282014-09-22 17:00:18 -0700205 FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
206 providerService.flowRemoved(rem1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700207 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
208
alshabibbb8b1282014-09-22 17:00:18 -0700209 providerService.flowRemoved(rem1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700210 validateEvents();
alshabibbb42cad2014-09-25 11:43:05 -0700211
212 FlowRule f3 = flowRule(flowRule(3, 3), FlowRuleState.ADDED);
213 providerService.flowAdded(f3);
214 validateEvents(RULE_ADDED);
215 providerService.flowRemoved(f3);
216 validateEvents();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700217 }
218
alshabibbb8b1282014-09-22 17:00:18 -0700219 @Test
220 public void flowMetrics() {
221 FlowRule f1 = flowRule(1, 1);
222 FlowRule f2 = flowRule(2, 2);
223 FlowRule f3 = flowRule(3, 3);
224
alshabibbb42cad2014-09-25 11:43:05 -0700225
alshabibbb8b1282014-09-22 17:00:18 -0700226 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
227 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
228 mgr.applyFlowRules(f1, f2, f3);
229
230 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2));
231
232 assertTrue("Entries should be added.",
233 validateState(FlowRuleState.PENDING_ADD, FlowRuleState.ADDED,
234 FlowRuleState.ADDED));
alshabibbb42cad2014-09-25 11:43:05 -0700235
236 validateEvents(RULE_UPDATED, RULE_UPDATED);
237 }
238
239 @Test
240 public void extraneousFlow() {
241 FlowRule f1 = flowRule(1, 1);
242 FlowRule f2 = flowRule(2, 2);
243 FlowRule f3 = flowRule(3, 3);
244
245 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
246 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
247 FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED);
248 mgr.applyFlowRules(f1, f2);
249
250 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2, updatedF3));
251
252 validateEvents(RULE_UPDATED, RULE_UPDATED);
253
254 }
255
256 /*
257 * Tests whether a rule that was marked for removal but no flowRemoved was received
258 * is indeed removed at the next stats update.
259 */
260 @Test
261 public void flowMissingRemove() {
262 FlowRule f1 = flowRule(1, 1);
263 FlowRule f2 = flowRule(2, 2);
264 FlowRule f3 = flowRule(3, 3);
265
266 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
267 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
268 mgr.applyFlowRules(f1, f2, f3);
269
270 mgr.removeFlowRules(f3);
271
272 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2));
273
274 validateEvents(RULE_UPDATED, RULE_UPDATED, RULE_REMOVED);
275
276 }
277
278 @Test
279 public void getByAppId() {
280 FlowRule f1 = flowRule(1, 1);
281 FlowRule f2 = flowRule(2, 2);
282 mgr.applyFlowRules(f1, f2);
283
284 assertTrue("should have two rules",
285 Lists.newLinkedList(mgr.getFlowRulesById(appId)).size() == 2);
286 }
287
288 @Test
289 public void removeByAppId() {
290 FlowRule f1 = flowRule(1, 1);
291 FlowRule f2 = flowRule(2, 2);
292 mgr.applyFlowRules(f1, f2);
293
294
295 mgr.removeFlowRulesById(appId);
296
297 //only check that we are in pending remove. Events and actual remove state will
298 // be set by flowRemoved call.
299 validateState(FlowRuleState.PENDING_REMOVE, FlowRuleState.PENDING_REMOVE);
alshabibbb8b1282014-09-22 17:00:18 -0700300 }
301
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700302 private static class TestListener implements FlowRuleListener {
303 final List<FlowRuleEvent> events = new ArrayList<>();
304
305 @Override
306 public void event(FlowRuleEvent event) {
307 events.add(event);
308 }
309 }
310
311 private static class TestDeviceService implements DeviceService {
312
313 @Override
314 public int getDeviceCount() {
315 return 0;
316 }
317
318 @Override
319 public Iterable<Device> getDevices() {
320 return null;
321 }
322
323 @Override
324 public Device getDevice(DeviceId deviceId) {
325 return DEV;
326 }
327
328 @Override
329 public MastershipRole getRole(DeviceId deviceId) {
330 return null;
331 }
332
333 @Override
334 public List<Port> getPorts(DeviceId deviceId) {
335 return null;
336 }
337
338 @Override
339 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
340 return null;
341 }
342
343 @Override
344 public boolean isAvailable(DeviceId deviceId) {
345 return false;
346 }
347
348 @Override
349 public void addListener(DeviceListener listener) {
350 }
351
352 @Override
353 public void removeListener(DeviceListener listener) {
354 }
355
356 }
357
358 private class TestProvider extends AbstractProvider implements FlowRuleProvider {
359
360 protected TestProvider(ProviderId id) {
361 super(PID);
362 }
363
364 @Override
365 public void applyFlowRule(FlowRule... flowRules) {
366 }
367
368 @Override
369 public void removeFlowRule(FlowRule... flowRules) {
370 }
371
alshabiba68eb962014-09-24 20:34:13 -0700372 @Override
373 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
374 }
375
376
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700377 }
378
379 private class TestSelector implements TrafficSelector {
380
381 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700382 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700383
384 public TestSelector(int val) {
385 testval = val;
386 }
387
388 @Override
389 public List<Criterion> criteria() {
390 return null;
391 }
392
393 @Override
394 public int hashCode() {
395 return testval;
396 }
397
398 @Override
399 public boolean equals(Object o) {
400 if (o instanceof TestSelector) {
401 return this.testval == ((TestSelector) o).testval;
402 }
403 return false;
404 }
405 }
406
407 private class TestTreatment implements TrafficTreatment {
408
409 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700410 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700411
412 public TestTreatment(int val) {
413 testval = val;
414 }
415
416 @Override
417 public List<Instruction> instructions() {
418 return null;
419 }
420
421 @Override
422 public int hashCode() {
423 return testval;
424 }
425
426 @Override
427 public boolean equals(Object o) {
428 if (o instanceof TestTreatment) {
429 return this.testval == ((TestTreatment) o).testval;
430 }
431 return false;
432 }
433
434 }
435
436}