blob: 4e634c95cc5d922100766bdd02db9a091e57b600 [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;
119 for (FlowRuleEvent e : listener.events) {
120 assertTrue("unexpected event", e.type().equals(events[i]));
121 i++;
122 }
123
124 assertEquals("mispredicted number of events",
125 events.length, listener.events.size());
126
127 listener.events.clear();
128 }
129
130 private int flowCount() {
131 return Sets.newHashSet(service.getFlowEntries(DID)).size();
132 }
133 @Test
134 public void getFlowEntries() {
135 assertTrue("store should be empty",
136 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
137 addFlowRule(1);
138 addFlowRule(2);
139 assertEquals("2 rules should exist", 2, flowCount());
140 validateEvents(RULE_ADDED, RULE_ADDED);
141
142 addFlowRule(1);
143 assertEquals("should still be 2 rules", 2, flowCount());
alshabib219ebaa2014-09-22 15:41:24 -0700144 validateEvents(RULE_UPDATED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700145 }
146
alshabibbb8b1282014-09-22 17:00:18 -0700147
148 //backing store is sensitive to the order of additions/removals
149 private boolean validateState(FlowRuleState... state) {
150 Iterable<FlowRule> rules = service.getFlowEntries(DID);
151 int i = 0;
152 for (FlowRule f : rules) {
153 if (f.state() != state[i]) {
154 return false;
155 }
156 i++;
157 }
158 return true;
159 }
160
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700161 @Test
162 public void applyFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700163
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700164 FlowRule r1 = flowRule(1, 1);
alshabiba68eb962014-09-24 20:34:13 -0700165 FlowRule r2 = flowRule(2, 2);
166 FlowRule r3 = flowRule(3, 3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700167
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700168 assertTrue("store should be empty",
169 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabib219ebaa2014-09-22 15:41:24 -0700170 mgr.applyFlowRules(r1, r2, r3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700171 assertEquals("3 rules should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700172 assertTrue("Entries should be pending add.",
173 validateState(FlowRuleState.PENDING_ADD, FlowRuleState.PENDING_ADD,
174 FlowRuleState.PENDING_ADD));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700175 }
176
177 @Test
178 public void removeFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700179 FlowRule f1 = addFlowRule(1);
180 FlowRule f2 = addFlowRule(2);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700181 addFlowRule(3);
182 assertEquals("3 rules should exist", 3, flowCount());
183 validateEvents(RULE_ADDED, RULE_ADDED, RULE_ADDED);
184
alshabibbb8b1282014-09-22 17:00:18 -0700185 FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
186 FlowRule rem2 = flowRule(f2, FlowRuleState.REMOVED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700187 mgr.removeFlowRules(rem1, rem2);
188 //removing from north, so no events generated
189 validateEvents();
alshabib219ebaa2014-09-22 15:41:24 -0700190 assertEquals("3 rule should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700191 assertTrue("Entries should be pending remove.",
192 validateState(FlowRuleState.CREATED, FlowRuleState.PENDING_REMOVE,
193 FlowRuleState.PENDING_REMOVE));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700194
195 mgr.removeFlowRules(rem1);
alshabib219ebaa2014-09-22 15:41:24 -0700196 assertEquals("3 rule should still exist", 3, flowCount());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700197 }
198
199 @Test
200 public void flowRemoved() {
alshabibbb8b1282014-09-22 17:00:18 -0700201 FlowRule f1 = addFlowRule(1);
alshabiba68eb962014-09-24 20:34:13 -0700202 service.removeFlowRules(f1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700203 addFlowRule(2);
alshabibbb8b1282014-09-22 17:00:18 -0700204 FlowRule rem1 = flowRule(f1, FlowRuleState.REMOVED);
205 providerService.flowRemoved(rem1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700206 validateEvents(RULE_ADDED, RULE_ADDED, RULE_REMOVED);
207
alshabibbb8b1282014-09-22 17:00:18 -0700208 providerService.flowRemoved(rem1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700209 validateEvents();
210 }
211
alshabibbb8b1282014-09-22 17:00:18 -0700212 @Test
213 public void flowMetrics() {
214 FlowRule f1 = flowRule(1, 1);
215 FlowRule f2 = flowRule(2, 2);
216 FlowRule f3 = flowRule(3, 3);
217
218 FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
219 FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
220 mgr.applyFlowRules(f1, f2, f3);
221
222 providerService.pushFlowMetrics(DID, Lists.newArrayList(updatedF1, updatedF2));
223
224 assertTrue("Entries should be added.",
225 validateState(FlowRuleState.PENDING_ADD, FlowRuleState.ADDED,
226 FlowRuleState.ADDED));
227 //TODO: add tests for flowmissing and extraneous flows
228 }
229
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700230 private static class TestListener implements FlowRuleListener {
231 final List<FlowRuleEvent> events = new ArrayList<>();
232
233 @Override
234 public void event(FlowRuleEvent event) {
235 events.add(event);
236 }
237 }
238
239 private static class TestDeviceService implements DeviceService {
240
241 @Override
242 public int getDeviceCount() {
243 return 0;
244 }
245
246 @Override
247 public Iterable<Device> getDevices() {
248 return null;
249 }
250
251 @Override
252 public Device getDevice(DeviceId deviceId) {
253 return DEV;
254 }
255
256 @Override
257 public MastershipRole getRole(DeviceId deviceId) {
258 return null;
259 }
260
261 @Override
262 public List<Port> getPorts(DeviceId deviceId) {
263 return null;
264 }
265
266 @Override
267 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
268 return null;
269 }
270
271 @Override
272 public boolean isAvailable(DeviceId deviceId) {
273 return false;
274 }
275
276 @Override
277 public void addListener(DeviceListener listener) {
278 }
279
280 @Override
281 public void removeListener(DeviceListener listener) {
282 }
283
284 }
285
286 private class TestProvider extends AbstractProvider implements FlowRuleProvider {
287
288 protected TestProvider(ProviderId id) {
289 super(PID);
290 }
291
292 @Override
293 public void applyFlowRule(FlowRule... flowRules) {
294 }
295
296 @Override
297 public void removeFlowRule(FlowRule... flowRules) {
298 }
299
alshabiba68eb962014-09-24 20:34:13 -0700300 @Override
301 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
302 }
303
304
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700305 }
306
307 private class TestSelector implements TrafficSelector {
308
309 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700310 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700311
312 public TestSelector(int val) {
313 testval = val;
314 }
315
316 @Override
317 public List<Criterion> criteria() {
318 return null;
319 }
320
321 @Override
322 public int hashCode() {
323 return testval;
324 }
325
326 @Override
327 public boolean equals(Object o) {
328 if (o instanceof TestSelector) {
329 return this.testval == ((TestSelector) o).testval;
330 }
331 return false;
332 }
333 }
334
335 private class TestTreatment implements TrafficTreatment {
336
337 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700338 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700339
340 public TestTreatment(int val) {
341 testval = val;
342 }
343
344 @Override
345 public List<Instruction> instructions() {
346 return null;
347 }
348
349 @Override
350 public int hashCode() {
351 return testval;
352 }
353
354 @Override
355 public boolean equals(Object o) {
356 if (o instanceof TestTreatment) {
357 return this.testval == ((TestTreatment) o).testval;
358 }
359 return false;
360 }
361
362 }
363
364}