blob: 0b451c061f9891e68783490eef499ee5e476c6ed [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;
alshabibba5ac482014-10-02 17:15:20 -070012import java.util.Collections;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070013import java.util.List;
alshabibba5ac482014-10-02 17:15:20 -070014import java.util.Set;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070015
16import org.junit.After;
17import org.junit.Before;
18import org.junit.Test;
alshabiba68eb962014-09-24 20:34:13 -070019import org.onlab.onos.ApplicationId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070020import org.onlab.onos.event.impl.TestEventDispatcher;
21import org.onlab.onos.net.DefaultDevice;
22import org.onlab.onos.net.Device;
23import org.onlab.onos.net.Device.Type;
24import org.onlab.onos.net.DeviceId;
25import org.onlab.onos.net.MastershipRole;
26import org.onlab.onos.net.Port;
27import org.onlab.onos.net.PortNumber;
28import org.onlab.onos.net.device.DeviceListener;
29import org.onlab.onos.net.device.DeviceService;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070030import org.onlab.onos.net.flow.DefaultFlowRule;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070031import org.onlab.onos.net.flow.FlowRule;
alshabibbb8b1282014-09-22 17:00:18 -070032import org.onlab.onos.net.flow.FlowRule.FlowRuleState;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070033import org.onlab.onos.net.flow.FlowRuleEvent;
34import org.onlab.onos.net.flow.FlowRuleListener;
35import org.onlab.onos.net.flow.FlowRuleProvider;
36import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
37import org.onlab.onos.net.flow.FlowRuleProviderService;
38import org.onlab.onos.net.flow.FlowRuleService;
39import org.onlab.onos.net.flow.TrafficSelector;
40import org.onlab.onos.net.flow.TrafficTreatment;
41import org.onlab.onos.net.flow.criteria.Criterion;
42import org.onlab.onos.net.flow.instructions.Instruction;
43import org.onlab.onos.net.provider.AbstractProvider;
44import org.onlab.onos.net.provider.ProviderId;
tomea961ff2014-10-01 12:45:15 -070045import org.onlab.onos.store.trivial.impl.SimpleFlowRuleStore;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070046
alshabibba5ac482014-10-02 17:15:20 -070047import com.google.common.collect.ImmutableList;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070048import com.google.common.collect.Lists;
49import com.google.common.collect.Sets;
50
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070051/**
52 * Test codifying the flow rule service & flow rule provider service contracts.
53 */
tom202175a2014-09-19 19:00:11 -070054public class FlowRuleManagerTest {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070055
tomf6ab2152014-09-18 12:08:29 -070056 private static final ProviderId PID = new ProviderId("of", "foo");
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070057 private static final DeviceId DID = DeviceId.deviceId("of:001");
alshabibba5ac482014-10-02 17:15:20 -070058 private static final int TIMEOUT = 10;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070059 private static final Device DEV = new DefaultDevice(
60 PID, DID, Type.SWITCH, "", "", "", "");
61
tom202175a2014-09-19 19:00:11 -070062 private FlowRuleManager mgr;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070063
64 protected FlowRuleService service;
65 protected FlowRuleProviderRegistry registry;
alshabibbb8b1282014-09-22 17:00:18 -070066 protected FlowRuleProviderService providerService;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070067 protected TestProvider provider;
68 protected TestListener listener = new TestListener();
alshabiba68eb962014-09-24 20:34:13 -070069 private ApplicationId appId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070070
71 @Before
72 public void setUp() {
tom202175a2014-09-19 19:00:11 -070073 mgr = new FlowRuleManager();
tombe988312014-09-19 18:38:47 -070074 mgr.store = new SimpleFlowRuleStore();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070075 mgr.eventDispatcher = new TestEventDispatcher();
76 mgr.deviceService = new TestDeviceService();
77 service = mgr;
78 registry = mgr;
79
80 mgr.activate();
81 mgr.addListener(listener);
82 provider = new TestProvider(PID);
alshabibbb8b1282014-09-22 17:00:18 -070083 providerService = registry.register(provider);
alshabiba68eb962014-09-24 20:34:13 -070084 appId = ApplicationId.getAppId();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070085 assertTrue("provider should be registered",
86 registry.getProviders().contains(provider.id()));
87 }
88
89 @After
90 public void tearDown() {
91 registry.unregister(provider);
92 assertFalse("provider should not be registered",
alshabib97044902014-09-18 14:52:16 -070093 registry.getProviders().contains(provider.id()));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070094 service.removeListener(listener);
95 mgr.deactivate();
96 mgr.eventDispatcher = null;
97 mgr.deviceService = null;
98 }
99
100 private FlowRule flowRule(int tsval, int trval) {
101 TestSelector ts = new TestSelector(tsval);
102 TestTreatment tr = new TestTreatment(trval);
alshabibba5ac482014-10-02 17:15:20 -0700103 return new DefaultFlowRule(DID, ts, tr, 0, appId, TIMEOUT);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700104 }
105
alshabibbb8b1282014-09-22 17:00:18 -0700106 private FlowRule flowRule(FlowRule rule, FlowRuleState state) {
107 return new DefaultFlowRule(rule, state);
108 }
109
110 private FlowRule addFlowRule(int hval) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700111 FlowRule rule = flowRule(hval, hval);
alshabibba5ac482014-10-02 17:15:20 -0700112 service.applyFlowRules(rule);
113
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700114 assertNotNull("rule should be found", service.getFlowEntries(DID));
alshabibbb8b1282014-09-22 17:00:18 -0700115 return rule;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700116 }
117
118 private void validateEvents(FlowRuleEvent.Type ... events) {
119 if (events == null) {
120 assertTrue("events generated", listener.events.isEmpty());
121 }
122
123 int i = 0;
alshabibbb42cad2014-09-25 11:43:05 -0700124 System.err.println("events :" + listener.events);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700125 for (FlowRuleEvent e : listener.events) {
126 assertTrue("unexpected event", e.type().equals(events[i]));
127 i++;
128 }
129
130 assertEquals("mispredicted number of events",
131 events.length, listener.events.size());
132
133 listener.events.clear();
134 }
135
136 private int flowCount() {
137 return Sets.newHashSet(service.getFlowEntries(DID)).size();
138 }
139 @Test
140 public void getFlowEntries() {
141 assertTrue("store should be empty",
142 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabibba5ac482014-10-02 17:15:20 -0700143 FlowRule f1 = addFlowRule(1);
144 FlowRule f2 = addFlowRule(2);
145
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700146 assertEquals("2 rules should exist", 2, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700147
148 providerService.pushFlowMetrics(DID, ImmutableList.of(f1, f2));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700149 validateEvents(RULE_ADDED, RULE_ADDED);
150
151 addFlowRule(1);
152 assertEquals("should still be 2 rules", 2, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700153
154 providerService.pushFlowMetrics(DID, ImmutableList.of(f1));
alshabib219ebaa2014-09-22 15:41:24 -0700155 validateEvents(RULE_UPDATED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700156 }
157
alshabibbb8b1282014-09-22 17:00:18 -0700158
159 //backing store is sensitive to the order of additions/removals
160 private boolean validateState(FlowRuleState... state) {
161 Iterable<FlowRule> rules = service.getFlowEntries(DID);
162 int i = 0;
163 for (FlowRule f : rules) {
164 if (f.state() != state[i]) {
165 return false;
166 }
167 i++;
168 }
169 return true;
170 }
171
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700172 @Test
173 public void applyFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700174
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700175 FlowRule r1 = flowRule(1, 1);
alshabiba68eb962014-09-24 20:34:13 -0700176 FlowRule r2 = flowRule(2, 2);
177 FlowRule r3 = flowRule(3, 3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700178
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700179 assertTrue("store should be empty",
180 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabib219ebaa2014-09-22 15:41:24 -0700181 mgr.applyFlowRules(r1, r2, r3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700182 assertEquals("3 rules should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700183 assertTrue("Entries should be pending add.",
184 validateState(FlowRuleState.PENDING_ADD, FlowRuleState.PENDING_ADD,
185 FlowRuleState.PENDING_ADD));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700186 }
187
188 @Test
189 public void removeFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700190 FlowRule f1 = addFlowRule(1);
191 FlowRule f2 = addFlowRule(2);
alshabibba5ac482014-10-02 17:15:20 -0700192 FlowRule f3 = addFlowRule(3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700193 assertEquals("3 rules should exist", 3, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700194
195 providerService.pushFlowMetrics(DID, ImmutableList.of(f1, f2, f3));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700196 validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED);
197
alshabibbb8b1282014-09-22 17:00:18 -0700198 FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
199 FlowRule rem2 = flowRule(f2, FlowRuleState.REMOVED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700200 mgr.removeFlowRules(rem1, rem2);
201 //removing from north, so no events generated
202 validateEvents();
alshabib219ebaa2014-09-22 15:41:24 -0700203 assertEquals("3 rule should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700204 assertTrue("Entries should be pending remove.",
205 validateState(FlowRuleState.CREATED, FlowRuleState.PENDING_REMOVE,
206 FlowRuleState.PENDING_REMOVE));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700207
208 mgr.removeFlowRules(rem1);
alshabib219ebaa2014-09-22 15:41:24 -0700209 assertEquals("3 rule should still exist", 3, flowCount());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700210 }
211
212 @Test
213 public void flowRemoved() {
alshabibbb8b1282014-09-22 17:00:18 -0700214 FlowRule f1 = addFlowRule(1);
alshabibba5ac482014-10-02 17:15:20 -0700215 FlowRule f2 = addFlowRule(2);
216 providerService.pushFlowMetrics(f1.deviceId(), ImmutableList.of(f1, f2));
alshabiba68eb962014-09-24 20:34:13 -0700217 service.removeFlowRules(f1);
alshabibbb8b1282014-09-22 17:00:18 -0700218 FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
219 providerService.flowRemoved(rem1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700220 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
221
alshabibbb8b1282014-09-22 17:00:18 -0700222 providerService.flowRemoved(rem1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700223 validateEvents();
alshabibbb42cad2014-09-25 11:43:05 -0700224
alshabibba5ac482014-10-02 17:15:20 -0700225 FlowRule f3 = flowRule(3, 3);
226 service.applyFlowRules(f3);
227 providerService.pushFlowMetrics(f3.deviceId(), Collections.singletonList(f3));
alshabibbb42cad2014-09-25 11:43:05 -0700228 validateEvents(RULE_ADDED);
alshabibba5ac482014-10-02 17:15:20 -0700229
alshabibbb42cad2014-09-25 11:43:05 -0700230 providerService.flowRemoved(f3);
231 validateEvents();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700232 }
233
alshabibbb8b1282014-09-22 17:00:18 -0700234 @Test
235 public void flowMetrics() {
236 FlowRule f1 = flowRule(1, 1);
237 FlowRule f2 = flowRule(2, 2);
238 FlowRule f3 = flowRule(3, 3);
239
alshabibbb42cad2014-09-25 11:43:05 -0700240
alshabibba5ac482014-10-02 17:15:20 -0700241
242 mgr.applyFlowRules(f1, f2, f3);
alshabibbb8b1282014-09-22 17:00:18 -0700243 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
244 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
alshabibbb8b1282014-09-22 17:00:18 -0700245
246 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2));
247
248 assertTrue("Entries should be added.",
249 validateState(FlowRuleState.PENDING_ADD, FlowRuleState.ADDED,
250 FlowRuleState.ADDED));
alshabibbb42cad2014-09-25 11:43:05 -0700251
alshabibba5ac482014-10-02 17:15:20 -0700252 validateEvents(RULE_ADDED, RULE_ADDED);
alshabibbb42cad2014-09-25 11:43:05 -0700253 }
254
255 @Test
256 public void extraneousFlow() {
257 FlowRule f1 = flowRule(1, 1);
258 FlowRule f2 = flowRule(2, 2);
259 FlowRule f3 = flowRule(3, 3);
alshabibba5ac482014-10-02 17:15:20 -0700260 mgr.applyFlowRules(f1, f2);
alshabibbb42cad2014-09-25 11:43:05 -0700261
262 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
263 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
264 FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED);
alshabibbb42cad2014-09-25 11:43:05 -0700265
266 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2, updatedF3));
267
alshabibba5ac482014-10-02 17:15:20 -0700268 validateEvents(RULE_ADDED, RULE_ADDED);
alshabibbb42cad2014-09-25 11:43:05 -0700269
270 }
271
272 /*
273 * Tests whether a rule that was marked for removal but no flowRemoved was received
274 * is indeed removed at the next stats update.
275 */
276 @Test
277 public void flowMissingRemove() {
278 FlowRule f1 = flowRule(1, 1);
279 FlowRule f2 = flowRule(2, 2);
280 FlowRule f3 = flowRule(3, 3);
281
282 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
283 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
284 mgr.applyFlowRules(f1, f2, f3);
285
286 mgr.removeFlowRules(f3);
287
288 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2));
289
alshabibba5ac482014-10-02 17:15:20 -0700290 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
alshabibbb42cad2014-09-25 11:43:05 -0700291
292 }
293
294 @Test
295 public void getByAppId() {
296 FlowRule f1 = flowRule(1, 1);
297 FlowRule f2 = flowRule(2, 2);
298 mgr.applyFlowRules(f1, f2);
299
300 assertTrue("should have two rules",
301 Lists.newLinkedList(mgr.getFlowRulesById(appId)).size() == 2);
302 }
303
304 @Test
305 public void removeByAppId() {
306 FlowRule f1 = flowRule(1, 1);
307 FlowRule f2 = flowRule(2, 2);
308 mgr.applyFlowRules(f1, f2);
309
310
311 mgr.removeFlowRulesById(appId);
312
313 //only check that we are in pending remove. Events and actual remove state will
314 // be set by flowRemoved call.
315 validateState(FlowRuleState.PENDING_REMOVE, FlowRuleState.PENDING_REMOVE);
alshabibbb8b1282014-09-22 17:00:18 -0700316 }
317
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700318 private static class TestListener implements FlowRuleListener {
319 final List<FlowRuleEvent> events = new ArrayList<>();
320
321 @Override
322 public void event(FlowRuleEvent event) {
323 events.add(event);
324 }
325 }
326
327 private static class TestDeviceService implements DeviceService {
328
329 @Override
330 public int getDeviceCount() {
331 return 0;
332 }
333
334 @Override
335 public Iterable<Device> getDevices() {
336 return null;
337 }
338
339 @Override
340 public Device getDevice(DeviceId deviceId) {
341 return DEV;
342 }
343
344 @Override
345 public MastershipRole getRole(DeviceId deviceId) {
346 return null;
347 }
348
349 @Override
350 public List<Port> getPorts(DeviceId deviceId) {
351 return null;
352 }
353
354 @Override
355 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
356 return null;
357 }
358
359 @Override
360 public boolean isAvailable(DeviceId deviceId) {
361 return false;
362 }
363
364 @Override
365 public void addListener(DeviceListener listener) {
366 }
367
368 @Override
369 public void removeListener(DeviceListener listener) {
370 }
371
372 }
373
374 private class TestProvider extends AbstractProvider implements FlowRuleProvider {
375
376 protected TestProvider(ProviderId id) {
377 super(PID);
378 }
379
380 @Override
381 public void applyFlowRule(FlowRule... flowRules) {
382 }
383
384 @Override
385 public void removeFlowRule(FlowRule... flowRules) {
386 }
387
alshabiba68eb962014-09-24 20:34:13 -0700388 @Override
389 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
390 }
391
392
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700393 }
394
395 private class TestSelector implements TrafficSelector {
396
397 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700398 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700399
400 public TestSelector(int val) {
401 testval = val;
402 }
403
404 @Override
alshabibba5ac482014-10-02 17:15:20 -0700405 public Set<Criterion> criteria() {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700406 return null;
407 }
408
409 @Override
410 public int hashCode() {
411 return testval;
412 }
413
414 @Override
415 public boolean equals(Object o) {
416 if (o instanceof TestSelector) {
417 return this.testval == ((TestSelector) o).testval;
418 }
419 return false;
420 }
421 }
422
423 private class TestTreatment implements TrafficTreatment {
424
425 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700426 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700427
428 public TestTreatment(int val) {
429 testval = val;
430 }
431
432 @Override
433 public List<Instruction> instructions() {
434 return null;
435 }
436
437 @Override
438 public int hashCode() {
439 return testval;
440 }
441
442 @Override
443 public boolean equals(Object o) {
444 if (o instanceof TestTreatment) {
445 return this.testval == ((TestTreatment) o).testval;
446 }
447 return false;
448 }
449
450 }
451
452}