blob: 7099464a999711d76eae7fb580d99fb0e7f0a72e [file] [log] [blame]
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.net.group.impl;
17
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080018import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.Collections;
21import java.util.List;
22
23import org.junit.After;
24import org.junit.Before;
25import org.junit.Test;
26import org.onlab.packet.MacAddress;
Michele Santuari4b6019e2014-12-19 11:31:45 +010027import org.onlab.packet.MplsLabel;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.DefaultApplicationId;
30import org.onosproject.core.DefaultGroupId;
31import org.onosproject.core.GroupId;
32import org.onosproject.event.impl.TestEventDispatcher;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.group.DefaultGroup;
38import org.onosproject.net.group.DefaultGroupBucket;
39import org.onosproject.net.group.DefaultGroupDescription;
40import org.onosproject.net.group.Group;
41import org.onosproject.net.group.GroupBucket;
42import org.onosproject.net.group.GroupBuckets;
43import org.onosproject.net.group.GroupDescription;
44import org.onosproject.net.group.GroupEvent;
45import org.onosproject.net.group.GroupKey;
46import org.onosproject.net.group.GroupListener;
47import org.onosproject.net.group.GroupOperation;
48import org.onosproject.net.group.GroupOperations;
49import org.onosproject.net.group.GroupProvider;
50import org.onosproject.net.group.GroupProviderRegistry;
51import org.onosproject.net.group.GroupProviderService;
52import org.onosproject.net.group.GroupService;
53import org.onosproject.net.group.StoredGroupEntry;
54import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
56import org.onosproject.store.trivial.impl.SimpleGroupStore;
57
58import com.google.common.collect.Iterables;
59
sangho7ff01812015-02-09 16:21:53 -080060import static org.junit.Assert.*;
61
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080062/**
63 * Test codifying the group service & group provider service contracts.
64 */
65public class GroupManagerTest {
66
67 private static final ProviderId PID = new ProviderId("of", "groupfoo");
68 private static final DeviceId DID = DeviceId.deviceId("of:001");
69
70 private GroupManager mgr;
71 private GroupService groupService;
72 private GroupProviderRegistry providerRegistry;
73 private TestGroupListener internalListener = new TestGroupListener();
74 private GroupListener listener = internalListener;
75 private TestGroupProvider internalProvider;
76 private GroupProvider provider;
77 private GroupProviderService providerService;
78 private ApplicationId appId;
79
80 @Before
81 public void setUp() {
82 mgr = new GroupManager();
83 groupService = mgr;
84 mgr.store = new SimpleGroupStore();
85 mgr.eventDispatcher = new TestEventDispatcher();
86 providerRegistry = mgr;
87
88 mgr.activate();
89 mgr.addListener(listener);
90
91 internalProvider = new TestGroupProvider(PID);
92 provider = internalProvider;
93 providerService = providerRegistry.register(provider);
94 appId = new DefaultApplicationId(2, "org.groupmanager.test");
95 assertTrue("provider should be registered",
96 providerRegistry.getProviders().contains(provider.id()));
97 }
98
99 @After
100 public void tearDown() {
101 providerRegistry.unregister(provider);
102 assertFalse("provider should not be registered",
103 providerRegistry.getProviders().contains(provider.id()));
104 mgr.removeListener(listener);
105 mgr.deactivate();
106 mgr.eventDispatcher = null;
107 }
108
109 private class TestGroupKey implements GroupKey {
110 private String groupId;
111
112 public TestGroupKey(String id) {
113 this.groupId = id;
114 }
115
116 public String id() {
117 return this.groupId;
118 }
119
120 @Override
121 public int hashCode() {
122 return groupId.hashCode();
123 }
124
125 @Override
126 public boolean equals(Object obj) {
127 if (obj instanceof TestGroupKey) {
128 return this.groupId.equals(((TestGroupKey) obj).id());
129 }
130 return false;
131 }
132 }
133
134 /**
135 * Tests group service north bound and south bound interfaces.
136 * The following operations are tested:
137 * a)Tests group creation before the device group AUDIT completes
138 * b)Tests initial device group AUDIT process
139 * c)Tests deletion process of any extraneous groups
140 * d)Tests execution of any pending group creation requests
141 * after the device group AUDIT completes
142 * e)Tests re-apply process of any missing groups
143 * f)Tests event notifications after receiving confirmation for
144 * any operations from data plane
145 * g)Tests group bucket modifications (additions and deletions)
146 * h)Tests group deletion
147 */
148 @Test
149 public void testGroupService() {
150 PortNumber[] ports1 = {PortNumber.portNumber(31),
151 PortNumber.portNumber(32)};
152 PortNumber[] ports2 = {PortNumber.portNumber(41),
153 PortNumber.portNumber(42)};
154 // Test Group creation before AUDIT process
155 TestGroupKey key = new TestGroupKey("group1BeforeAudit");
156 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
157 List<PortNumber> outPorts = new ArrayList<PortNumber>();
158 outPorts.addAll(Arrays.asList(ports1));
159 outPorts.addAll(Arrays.asList(ports2));
160 for (PortNumber portNumber: outPorts) {
161 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
162 tBuilder.setOutput(portNumber)
163 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
164 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
165 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100166 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800167 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
168 tBuilder.build()));
169 }
170 GroupBuckets groupBuckets = new GroupBuckets(buckets);
171 GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
172 Group.Type.SELECT,
173 groupBuckets,
174 key,
175 appId);
176 groupService.addGroup(newGroupDesc);
177 internalProvider.validate(DID, null);
178 assertEquals(null, groupService.getGroup(DID, key));
179 assertEquals(0, Iterables.size(groupService.getGroups(DID, appId)));
180
181 // Test initial group audit process
182 GroupId gId1 = new DefaultGroupId(1);
183 Group group1 = createSouthboundGroupEntry(gId1,
184 Arrays.asList(ports1),
185 0);
186 GroupId gId2 = new DefaultGroupId(2);
187 // Non zero reference count will make the group manager to queue
188 // the extraneous groups until reference count is zero.
189 Group group2 = createSouthboundGroupEntry(gId2,
190 Arrays.asList(ports2),
191 2);
192 List<Group> groupEntries = Arrays.asList(group1, group2);
193 providerService.pushGroupMetrics(DID, groupEntries);
194 // First group metrics would trigger the device audit completion
195 // post which all pending group requests are also executed.
196 Group createdGroup = groupService.getGroup(DID, key);
197 int createdGroupId = createdGroup.id().id();
198 assertNotEquals(gId1.id(), createdGroupId);
199 assertNotEquals(gId2.id(), createdGroupId);
200 List<GroupOperation> expectedGroupOps = Arrays.asList(
201 GroupOperation.createDeleteGroupOperation(gId1,
202 Group.Type.SELECT),
203 GroupOperation.createAddGroupOperation(
204 createdGroup.id(),
205 Group.Type.SELECT,
206 groupBuckets));
207 internalProvider.validate(DID, expectedGroupOps);
208
209 group1 = createSouthboundGroupEntry(gId1,
210 Arrays.asList(ports1),
211 0);
212 group2 = createSouthboundGroupEntry(gId2,
213 Arrays.asList(ports2),
214 0);
215 groupEntries = Arrays.asList(group1, group2);
216 providerService.pushGroupMetrics(DID, groupEntries);
217 expectedGroupOps = Arrays.asList(
218 GroupOperation.createDeleteGroupOperation(gId1,
219 Group.Type.SELECT),
220 GroupOperation.createDeleteGroupOperation(gId2,
221 Group.Type.SELECT),
222 GroupOperation.createAddGroupOperation(createdGroup.id(),
223 Group.Type.SELECT,
224 groupBuckets));
225 internalProvider.validate(DID, expectedGroupOps);
226
227 createdGroup = new DefaultGroup(createdGroup.id(),
228 DID,
229 Group.Type.SELECT,
230 groupBuckets);
231 groupEntries = Arrays.asList(createdGroup);
232 providerService.pushGroupMetrics(DID, groupEntries);
233 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_ADDED));
234
235 // Test group add bucket operations
236 TestGroupKey addKey = new TestGroupKey("group1AddBuckets");
237 PortNumber[] addPorts = {PortNumber.portNumber(51),
238 PortNumber.portNumber(52)};
239 outPorts.clear();
240 outPorts.addAll(Arrays.asList(addPorts));
241 List<GroupBucket> addBuckets = new ArrayList<GroupBucket>();
242 for (PortNumber portNumber: outPorts) {
243 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
244 tBuilder.setOutput(portNumber)
245 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
246 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
247 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100248 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800249 addBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
250 tBuilder.build()));
251 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
252 tBuilder.build()));
253 }
254 GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets);
255 groupService.addBucketsToGroup(DID,
256 key,
257 groupAddBuckets,
258 addKey,
259 appId);
260 GroupBuckets updatedBuckets = new GroupBuckets(buckets);
261 expectedGroupOps = Arrays.asList(
262 GroupOperation.createModifyGroupOperation(createdGroup.id(),
263 Group.Type.SELECT,
264 updatedBuckets));
265 internalProvider.validate(DID, expectedGroupOps);
266 Group existingGroup = groupService.getGroup(DID, addKey);
267 groupEntries = Arrays.asList(existingGroup);
268 providerService.pushGroupMetrics(DID, groupEntries);
269 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATED));
270
271 // Test group remove bucket operations
272 TestGroupKey removeKey = new TestGroupKey("group1RemoveBuckets");
273 PortNumber[] removePorts = {PortNumber.portNumber(31),
274 PortNumber.portNumber(32)};
275 outPorts.clear();
276 outPorts.addAll(Arrays.asList(removePorts));
277 List<GroupBucket> removeBuckets = new ArrayList<GroupBucket>();
278 for (PortNumber portNumber: outPorts) {
279 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
280 tBuilder.setOutput(portNumber)
281 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
282 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
283 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100284 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800285 removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
286 tBuilder.build()));
287 buckets.remove(DefaultGroupBucket.createSelectGroupBucket(
288 tBuilder.build()));
289 }
290 GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets);
291 groupService.removeBucketsFromGroup(DID,
292 addKey,
293 groupRemoveBuckets,
294 removeKey,
295 appId);
296 updatedBuckets = new GroupBuckets(buckets);
297 expectedGroupOps = Arrays.asList(
298 GroupOperation.createModifyGroupOperation(createdGroup.id(),
299 Group.Type.SELECT,
300 updatedBuckets));
301 internalProvider.validate(DID, expectedGroupOps);
302 existingGroup = groupService.getGroup(DID, removeKey);
303 groupEntries = Arrays.asList(existingGroup);
304 providerService.pushGroupMetrics(DID, groupEntries);
305 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATED));
306
307 // Test group remove operations
308 groupService.removeGroup(DID, removeKey, appId);
309 expectedGroupOps = Arrays.asList(
310 GroupOperation.createDeleteGroupOperation(createdGroup.id(),
311 Group.Type.SELECT));
312 internalProvider.validate(DID, expectedGroupOps);
313 groupEntries = Collections.emptyList();
314 providerService.pushGroupMetrics(DID, groupEntries);
315 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVED));
316 }
317
sangho7ff01812015-02-09 16:21:53 -0800318 /**
319 * Test GroupOperationFailure function in Group Manager.
320 * a)GroupAddFailure
321 * b)GroupUpdateFailure
322 * c)GroupRemoteFailure
323 */
324 @Test
325 public void testGroupOperationFailure() {
326 PortNumber[] ports1 = {PortNumber.portNumber(31),
327 PortNumber.portNumber(32)};
328 PortNumber[] ports2 = {PortNumber.portNumber(41),
329 PortNumber.portNumber(42)};
330 // Test Group creation before AUDIT process
331 TestGroupKey key = new TestGroupKey("group1BeforeAudit");
332 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
333 List<PortNumber> outPorts = new ArrayList<PortNumber>();
334 outPorts.addAll(Arrays.asList(ports1));
335 outPorts.addAll(Arrays.asList(ports2));
336 for (PortNumber portNumber: outPorts) {
337 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
338 tBuilder.setOutput(portNumber)
339 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
340 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
341 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100342 .setMpls(MplsLabel.mplsLabel(106));
sangho7ff01812015-02-09 16:21:53 -0800343 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
344 tBuilder.build()));
345 }
346 GroupBuckets groupBuckets = new GroupBuckets(buckets);
347 GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
348 Group.Type.SELECT,
349 groupBuckets,
350 key,
351 appId);
352 groupService.addGroup(newGroupDesc);
353
354 // Test initial group audit process
355 GroupId gId1 = new DefaultGroupId(1);
356 Group group1 = createSouthboundGroupEntry(gId1,
357 Arrays.asList(ports1),
358 0);
359 GroupId gId2 = new DefaultGroupId(2);
360 // Non zero reference count will make the group manager to queue
361 // the extraneous groups until reference count is zero.
362 Group group2 = createSouthboundGroupEntry(gId2,
363 Arrays.asList(ports2),
364 2);
365 List<Group> groupEntries = Arrays.asList(group1, group2);
366 providerService.pushGroupMetrics(DID, groupEntries);
367 Group createdGroup = groupService.getGroup(DID, key);
368
369 // Group Add failure test
370 GroupOperation groupAddOp = GroupOperation.
371 createAddGroupOperation(createdGroup.id(),
372 createdGroup.type(),
373 createdGroup.buckets());
374 providerService.groupOperationFailed(DID, groupAddOp);
375 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_ADD_FAILED));
376
377 // Group Mod failure test
378 groupService.addGroup(newGroupDesc);
379 createdGroup = groupService.getGroup(DID, key);
380 assertNotNull(createdGroup);
381
382 GroupOperation groupModOp = GroupOperation.
383 createModifyGroupOperation(createdGroup.id(),
384 createdGroup.type(),
385 createdGroup.buckets());
386 providerService.groupOperationFailed(DID, groupModOp);
387 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATE_FAILED));
388
389 // Group Delete failure test
390 groupService.addGroup(newGroupDesc);
391 createdGroup = groupService.getGroup(DID, key);
392 assertNotNull(createdGroup);
393
394 GroupOperation groupDelOp = GroupOperation.
395 createDeleteGroupOperation(createdGroup.id(),
396 createdGroup.type());
397 providerService.groupOperationFailed(DID, groupDelOp);
398 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVE_FAILED));
399
400 }
401
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800402 private Group createSouthboundGroupEntry(GroupId gId,
403 List<PortNumber> ports,
404 long referenceCount) {
405 List<PortNumber> outPorts = new ArrayList<PortNumber>();
406 outPorts.addAll(ports);
407
408 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
409 for (PortNumber portNumber: outPorts) {
410 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
411 tBuilder.setOutput(portNumber)
412 .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
413 .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
414 .pushMpls()
Michele Santuari4b6019e2014-12-19 11:31:45 +0100415 .setMpls(MplsLabel.mplsLabel(106));
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800416 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
417 tBuilder.build()));
418 }
419 GroupBuckets groupBuckets = new GroupBuckets(buckets);
420 StoredGroupEntry group = new DefaultGroup(
421 gId, DID, Group.Type.SELECT, groupBuckets);
422 group.setReferenceCount(referenceCount);
423 return group;
424 }
425
426 private static class TestGroupListener implements GroupListener {
427 final List<GroupEvent> events = new ArrayList<>();
428
429 @Override
430 public void event(GroupEvent event) {
431 events.add(event);
432 }
433
434 public void validateEvent(List<GroupEvent.Type> expectedEvents) {
435 int i = 0;
436 System.err.println("events :" + events);
437 for (GroupEvent e : events) {
438 assertEquals("unexpected event", expectedEvents.get(i), e.type());
439 i++;
440 }
441 assertEquals("mispredicted number of events",
442 expectedEvents.size(), events.size());
443 events.clear();
444 }
445 }
446
447 private class TestGroupProvider
448 extends AbstractProvider implements GroupProvider {
449 DeviceId lastDeviceId;
450 List<GroupOperation> groupOperations = new ArrayList<GroupOperation>();
451
452 protected TestGroupProvider(ProviderId id) {
453 super(id);
454 }
455
456 @Override
457 public void performGroupOperation(DeviceId deviceId,
458 GroupOperations groupOps) {
459 lastDeviceId = deviceId;
460 groupOperations.addAll(groupOps.operations());
461 }
462
463 public void validate(DeviceId expectedDeviceId,
464 List<GroupOperation> expectedGroupOps) {
465 if (expectedGroupOps == null) {
466 assertTrue("events generated", groupOperations.isEmpty());
467 return;
468 }
469
470 assertEquals(lastDeviceId, expectedDeviceId);
471 assertTrue((this.groupOperations.containsAll(expectedGroupOps) &&
472 expectedGroupOps.containsAll(groupOperations)));
473
474 groupOperations.clear();
475 lastDeviceId = null;
476 }
477
478 }
479
480}
481
482