sangho
Committed by Pavlin Radoslavov

ONOS-944: Implemented a Group operation failure handler in GroupManger and SimpleGroupStore.

Change-Id: Ib3be4d534ceff04af2dad0c062fd4cd63d49ee82
...@@ -41,6 +41,21 @@ public class GroupEvent extends AbstractEvent<GroupEvent.Type, Group> { ...@@ -41,6 +41,21 @@ public class GroupEvent extends AbstractEvent<GroupEvent.Type, Group> {
41 */ 41 */
42 GROUP_UPDATED, 42 GROUP_UPDATED,
43 43
44 + /**
45 + * Signifies that a request to create Group has failed.
46 + */
47 + GROUP_ADD_FAILED,
48 +
49 + /**
50 + * Signifies that a request to remove Group has failed.
51 + */
52 + GROUP_REMOVE_FAILED,
53 +
54 + /**
55 + * Signifies that a request to update Group has failed.
56 + */
57 + GROUP_UPDATE_FAILED,
58 +
44 // internal event between Manager <-> Store 59 // internal event between Manager <-> Store
45 60
46 /* 61 /*
...@@ -55,6 +70,8 @@ public class GroupEvent extends AbstractEvent<GroupEvent.Type, Group> { ...@@ -55,6 +70,8 @@ public class GroupEvent extends AbstractEvent<GroupEvent.Type, Group> {
55 * Signifies that a request to delete Group has been added to the store. 70 * Signifies that a request to delete Group has been added to the store.
56 */ 71 */
57 GROUP_REMOVE_REQUESTED, 72 GROUP_REMOVE_REQUESTED,
73 +
74 +
58 } 75 }
59 76
60 /** 77 /**
......
...@@ -29,9 +29,10 @@ public interface GroupProviderService extends ProviderService<GroupProvider> { ...@@ -29,9 +29,10 @@ public interface GroupProviderService extends ProviderService<GroupProvider> {
29 /** 29 /**
30 * Notifies core if any failure from data plane during group operations. 30 * Notifies core if any failure from data plane during group operations.
31 * 31 *
32 + * @param deviceId the device ID
32 * @param operation offended group operation 33 * @param operation offended group operation
33 */ 34 */
34 - void groupOperationFailed(GroupOperation operation); 35 + void groupOperationFailed(DeviceId deviceId, GroupOperation operation);
35 36
36 /** 37 /**
37 * Pushes the collection of group detected in the data plane along 38 * Pushes the collection of group detected in the data plane along
......
...@@ -143,4 +143,12 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { ...@@ -143,4 +143,12 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> {
143 * @return initial group audit status 143 * @return initial group audit status
144 */ 144 */
145 boolean deviceInitialAuditStatus(DeviceId deviceId); 145 boolean deviceInitialAuditStatus(DeviceId deviceId);
146 +
147 + /**
148 + * Indicates the group operations failed.
149 + *
150 + * @param deviceId the device ID
151 + * @param operation the group operation failed
152 + */
153 + void groupOperationFailed(DeviceId deviceId, GroupOperation operation);
146 } 154 }
......
...@@ -263,6 +263,9 @@ public class GroupManager ...@@ -263,6 +263,9 @@ public class GroupManager
263 case GROUP_ADDED: 263 case GROUP_ADDED:
264 case GROUP_UPDATED: 264 case GROUP_UPDATED:
265 case GROUP_REMOVED: 265 case GROUP_REMOVED:
266 + case GROUP_ADD_FAILED:
267 + case GROUP_UPDATE_FAILED:
268 + case GROUP_REMOVE_FAILED:
266 eventDispatcher.post(event); 269 eventDispatcher.post(event);
267 break; 270 break;
268 271
...@@ -281,9 +284,9 @@ public class GroupManager ...@@ -281,9 +284,9 @@ public class GroupManager
281 } 284 }
282 285
283 @Override 286 @Override
284 - public void groupOperationFailed(GroupOperation operation) { 287 + public void groupOperationFailed(DeviceId deviceId,
285 - // TODO Auto-generated method stub 288 + GroupOperation operation) {
286 - 289 + store.groupOperationFailed(deviceId, operation);
287 } 290 }
288 291
289 private void groupMissing(Group group) { 292 private void groupMissing(Group group) {
......
...@@ -15,11 +15,6 @@ ...@@ -15,11 +15,6 @@
15 */ 15 */
16 package org.onosproject.net.group.impl; 16 package org.onosproject.net.group.impl;
17 17
18 -import static org.junit.Assert.assertEquals;
19 -import static org.junit.Assert.assertFalse;
20 -import static org.junit.Assert.assertNotEquals;
21 -import static org.junit.Assert.assertTrue;
22 -
23 import java.util.ArrayList; 18 import java.util.ArrayList;
24 import java.util.Arrays; 19 import java.util.Arrays;
25 import java.util.Collections; 20 import java.util.Collections;
...@@ -61,6 +56,8 @@ import org.onosproject.store.trivial.impl.SimpleGroupStore; ...@@ -61,6 +56,8 @@ import org.onosproject.store.trivial.impl.SimpleGroupStore;
61 56
62 import com.google.common.collect.Iterables; 57 import com.google.common.collect.Iterables;
63 58
59 +import static org.junit.Assert.*;
60 +
64 /** 61 /**
65 * Test codifying the group service & group provider service contracts. 62 * Test codifying the group service & group provider service contracts.
66 */ 63 */
...@@ -317,6 +314,90 @@ public class GroupManagerTest { ...@@ -317,6 +314,90 @@ public class GroupManagerTest {
317 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVED)); 314 internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVED));
318 } 315 }
319 316
317 + /**
318 + * Test GroupOperationFailure function in Group Manager.
319 + * a)GroupAddFailure
320 + * b)GroupUpdateFailure
321 + * c)GroupRemoteFailure
322 + */
323 + @Test
324 + public void testGroupOperationFailure() {
325 + PortNumber[] ports1 = {PortNumber.portNumber(31),
326 + PortNumber.portNumber(32)};
327 + PortNumber[] ports2 = {PortNumber.portNumber(41),
328 + PortNumber.portNumber(42)};
329 + // Test Group creation before AUDIT process
330 + TestGroupKey key = new TestGroupKey("group1BeforeAudit");
331 + List<GroupBucket> buckets = new ArrayList<GroupBucket>();
332 + List<PortNumber> outPorts = new ArrayList<PortNumber>();
333 + outPorts.addAll(Arrays.asList(ports1));
334 + outPorts.addAll(Arrays.asList(ports2));
335 + for (PortNumber portNumber: outPorts) {
336 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
337 + tBuilder.setOutput(portNumber)
338 + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
339 + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
340 + .pushMpls()
341 + .setMpls(106);
342 + buckets.add(DefaultGroupBucket.createSelectGroupBucket(
343 + tBuilder.build()));
344 + }
345 + GroupBuckets groupBuckets = new GroupBuckets(buckets);
346 + GroupDescription newGroupDesc = new DefaultGroupDescription(DID,
347 + Group.Type.SELECT,
348 + groupBuckets,
349 + key,
350 + appId);
351 + groupService.addGroup(newGroupDesc);
352 +
353 + // Test initial group audit process
354 + GroupId gId1 = new DefaultGroupId(1);
355 + Group group1 = createSouthboundGroupEntry(gId1,
356 + Arrays.asList(ports1),
357 + 0);
358 + GroupId gId2 = new DefaultGroupId(2);
359 + // Non zero reference count will make the group manager to queue
360 + // the extraneous groups until reference count is zero.
361 + Group group2 = createSouthboundGroupEntry(gId2,
362 + Arrays.asList(ports2),
363 + 2);
364 + List<Group> groupEntries = Arrays.asList(group1, group2);
365 + providerService.pushGroupMetrics(DID, groupEntries);
366 + Group createdGroup = groupService.getGroup(DID, key);
367 +
368 + // Group Add failure test
369 + GroupOperation groupAddOp = GroupOperation.
370 + createAddGroupOperation(createdGroup.id(),
371 + createdGroup.type(),
372 + createdGroup.buckets());
373 + providerService.groupOperationFailed(DID, groupAddOp);
374 + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_ADD_FAILED));
375 +
376 + // Group Mod failure test
377 + groupService.addGroup(newGroupDesc);
378 + createdGroup = groupService.getGroup(DID, key);
379 + assertNotNull(createdGroup);
380 +
381 + GroupOperation groupModOp = GroupOperation.
382 + createModifyGroupOperation(createdGroup.id(),
383 + createdGroup.type(),
384 + createdGroup.buckets());
385 + providerService.groupOperationFailed(DID, groupModOp);
386 + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATE_FAILED));
387 +
388 + // Group Delete failure test
389 + groupService.addGroup(newGroupDesc);
390 + createdGroup = groupService.getGroup(DID, key);
391 + assertNotNull(createdGroup);
392 +
393 + GroupOperation groupDelOp = GroupOperation.
394 + createDeleteGroupOperation(createdGroup.id(),
395 + createdGroup.type());
396 + providerService.groupOperationFailed(DID, groupDelOp);
397 + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVE_FAILED));
398 +
399 + }
400 +
320 private Group createSouthboundGroupEntry(GroupId gId, 401 private Group createSouthboundGroupEntry(GroupId gId,
321 List<PortNumber> ports, 402 List<PortNumber> ports,
322 long referenceCount) { 403 long referenceCount) {
......
...@@ -43,6 +43,7 @@ import org.onosproject.net.group.GroupDescription; ...@@ -43,6 +43,7 @@ import org.onosproject.net.group.GroupDescription;
43 import org.onosproject.net.group.GroupEvent; 43 import org.onosproject.net.group.GroupEvent;
44 import org.onosproject.net.group.GroupEvent.Type; 44 import org.onosproject.net.group.GroupEvent.Type;
45 import org.onosproject.net.group.GroupKey; 45 import org.onosproject.net.group.GroupKey;
46 +import org.onosproject.net.group.GroupOperation;
46 import org.onosproject.net.group.GroupStore; 47 import org.onosproject.net.group.GroupStore;
47 import org.onosproject.net.group.GroupStoreDelegate; 48 import org.onosproject.net.group.GroupStoreDelegate;
48 import org.onosproject.net.group.StoredGroupEntry; 49 import org.onosproject.net.group.StoredGroupEntry;
...@@ -474,6 +475,41 @@ public class SimpleGroupStore ...@@ -474,6 +475,41 @@ public class SimpleGroupStore
474 } 475 }
475 476
476 @Override 477 @Override
478 + public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
479 +
480 + StoredGroupEntry existing = (groupEntriesById.get(
481 + deviceId) != null) ?
482 + groupEntriesById.get(deviceId).get(operation.groupId()) :
483 + null;
484 +
485 + if (existing == null) {
486 + log.warn("No group entry with ID {} found ", operation.groupId());
487 + return;
488 + }
489 +
490 + switch (operation.opType()) {
491 + case ADD:
492 + notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing));
493 + break;
494 + case MODIFY:
495 + notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing));
496 + break;
497 + case DELETE:
498 + notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_FAILED, existing));
499 + break;
500 + default:
501 + log.warn("Unknown group operation type {}", operation.opType());
502 + }
503 +
504 + ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
505 + getGroupKeyTable(existing.deviceId());
506 + ConcurrentMap<GroupId, StoredGroupEntry> idTable =
507 + getGroupIdTable(existing.deviceId());
508 + idTable.remove(existing.id());
509 + keyTable.remove(existing.appCookie());
510 + }
511 +
512 + @Override
477 public void addOrUpdateExtraneousGroupEntry(Group group) { 513 public void addOrUpdateExtraneousGroupEntry(Group group) {
478 ConcurrentMap<GroupId, Group> extraneousIdTable = 514 ConcurrentMap<GroupId, Group> extraneousIdTable =
479 getExtraneousGroupIdTable(group.deviceId()); 515 getExtraneousGroupIdTable(group.deviceId());
...@@ -497,4 +533,6 @@ public class SimpleGroupStore ...@@ -497,4 +533,6 @@ public class SimpleGroupStore
497 return FluentIterable.from( 533 return FluentIterable.from(
498 getExtraneousGroupIdTable(deviceId).values()); 534 getExtraneousGroupIdTable(deviceId).values());
499 } 535 }
536 +
537 +
500 } 538 }
......
...@@ -40,6 +40,7 @@ import org.onosproject.net.group.GroupBuckets; ...@@ -40,6 +40,7 @@ import org.onosproject.net.group.GroupBuckets;
40 import org.onosproject.net.group.GroupDescription; 40 import org.onosproject.net.group.GroupDescription;
41 import org.onosproject.net.group.GroupEvent; 41 import org.onosproject.net.group.GroupEvent;
42 import org.onosproject.net.group.GroupKey; 42 import org.onosproject.net.group.GroupKey;
43 +import org.onosproject.net.group.GroupOperation;
43 import org.onosproject.net.group.GroupStore.UpdateType; 44 import org.onosproject.net.group.GroupStore.UpdateType;
44 import org.onosproject.net.group.GroupStoreDelegate; 45 import org.onosproject.net.group.GroupStoreDelegate;
45 46
...@@ -129,6 +130,18 @@ public class SimpleGroupStoreTest { ...@@ -129,6 +130,18 @@ public class SimpleGroupStoreTest {
129 createdGroupId = event.subject().id(); 130 createdGroupId = event.subject().id();
130 assertEquals(Group.GroupState.PENDING_DELETE, 131 assertEquals(Group.GroupState.PENDING_DELETE,
131 event.subject().state()); 132 event.subject().state());
133 + } else if (expectedEvent == GroupEvent.Type.GROUP_ADD_FAILED) {
134 + createdGroupId = event.subject().id();
135 + assertEquals(Group.GroupState.PENDING_ADD,
136 + event.subject().state());
137 + } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_FAILED) {
138 + createdGroupId = event.subject().id();
139 + assertEquals(Group.GroupState.PENDING_UPDATE,
140 + event.subject().state());
141 + } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_FAILED) {
142 + createdGroupId = event.subject().id();
143 + assertEquals(Group.GroupState.PENDING_DELETE,
144 + event.subject().state());
132 } 145 }
133 } 146 }
134 147
...@@ -310,6 +323,92 @@ public class SimpleGroupStoreTest { ...@@ -310,6 +323,92 @@ public class SimpleGroupStoreTest {
310 323
311 simpleGroupStore.unsetDelegate(removeGroupEntryDelegate); 324 simpleGroupStore.unsetDelegate(removeGroupEntryDelegate);
312 325
326 +
327 + }
328 +
329 + @Test
330 + public void testGroupOperationFailure() {
331 +
332 + simpleGroupStore.deviceInitialAuditCompleted(D1);
333 +
334 + ApplicationId appId =
335 + new DefaultApplicationId(2, "org.groupstore.test");
336 + TestGroupKey key = new TestGroupKey("group1");
337 + PortNumber[] ports = {PortNumber.portNumber(31),
338 + PortNumber.portNumber(32)};
339 + List<PortNumber> outPorts = new ArrayList<PortNumber>();
340 + outPorts.add(ports[0]);
341 + outPorts.add(ports[1]);
342 +
343 + List<GroupBucket> buckets = new ArrayList<GroupBucket>();
344 + for (PortNumber portNumber: outPorts) {
345 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
346 + tBuilder.setOutput(portNumber)
347 + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02"))
348 + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
349 + .pushMpls()
350 + .setMpls(106);
351 + buckets.add(DefaultGroupBucket.createSelectGroupBucket(
352 + tBuilder.build()));
353 + }
354 + GroupBuckets groupBuckets = new GroupBuckets(buckets);
355 + GroupDescription groupDesc = new DefaultGroupDescription(
356 + D1,
357 + Group.Type.SELECT,
358 + groupBuckets,
359 + key,
360 + appId);
361 + InternalGroupStoreDelegate checkStoreGroupDelegate =
362 + new InternalGroupStoreDelegate(key,
363 + groupBuckets,
364 + GroupEvent.Type.GROUP_ADD_REQUESTED);
365 + simpleGroupStore.setDelegate(checkStoreGroupDelegate);
366 + // Testing storeGroup operation
367 + simpleGroupStore.storeGroupDescription(groupDesc);
368 + simpleGroupStore.unsetDelegate(checkStoreGroupDelegate);
369 +
370 + // Testing Group add operation failure
371 + Group createdGroup = simpleGroupStore.getGroup(D1, key);
372 + checkStoreGroupDelegate.verifyGroupId(createdGroup.id());
373 +
374 + GroupOperation groupAddOp = GroupOperation.
375 + createAddGroupOperation(createdGroup.id(),
376 + createdGroup.type(),
377 + createdGroup.buckets());
378 + InternalGroupStoreDelegate checkGroupAddFailureDelegate =
379 + new InternalGroupStoreDelegate(key,
380 + groupBuckets,
381 + GroupEvent.Type.GROUP_ADD_FAILED);
382 + simpleGroupStore.setDelegate(checkGroupAddFailureDelegate);
383 + simpleGroupStore.groupOperationFailed(D1, groupAddOp);
384 +
385 +
386 + // Testing Group modify operation failure
387 + simpleGroupStore.unsetDelegate(checkGroupAddFailureDelegate);
388 + GroupOperation groupModOp = GroupOperation.
389 + createModifyGroupOperation(createdGroup.id(),
390 + createdGroup.type(),
391 + createdGroup.buckets());
392 + InternalGroupStoreDelegate checkGroupModFailureDelegate =
393 + new InternalGroupStoreDelegate(key,
394 + groupBuckets,
395 + GroupEvent.Type.GROUP_UPDATE_FAILED);
396 + simpleGroupStore.setDelegate(checkGroupModFailureDelegate);
397 + simpleGroupStore.groupOperationFailed(D1, groupModOp);
398 +
399 + // Testing Group modify operation failure
400 + simpleGroupStore.unsetDelegate(checkGroupModFailureDelegate);
401 + GroupOperation groupDelOp = GroupOperation.
402 + createDeleteGroupOperation(createdGroup.id(),
403 + createdGroup.type());
404 + InternalGroupStoreDelegate checkGroupDelFailureDelegate =
405 + new InternalGroupStoreDelegate(key,
406 + groupBuckets,
407 + GroupEvent.Type.GROUP_REMOVE_FAILED);
408 + simpleGroupStore.setDelegate(checkGroupDelFailureDelegate);
409 + simpleGroupStore.groupOperationFailed(D1, groupDelOp);
410 +
411 +
313 } 412 }
314 } 413 }
315 414
......
...@@ -282,8 +282,10 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -282,8 +282,10 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
282 } else { 282 } else {
283 GroupOperation operation = 283 GroupOperation operation =
284 pendingGroupOperations.get(pendingGroupId); 284 pendingGroupOperations.get(pendingGroupId);
285 + DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
285 if (operation != null) { 286 if (operation != null) {
286 - providerService.groupOperationFailed(operation); 287 + providerService.groupOperationFailed(deviceId,
288 + operation);
287 pendingGroupOperations.remove(pendingGroupId); 289 pendingGroupOperations.remove(pendingGroupId);
288 pendingXidMaps.remove(pendingGroupId); 290 pendingXidMaps.remove(pendingGroupId);
289 log.warn("Received an group mod error {}", msg); 291 log.warn("Received an group mod error {}", msg);
......
...@@ -177,7 +177,7 @@ public class OpenFlowGroupProviderTest { ...@@ -177,7 +177,7 @@ public class OpenFlowGroupProviderTest {
177 } 177 }
178 178
179 @Override 179 @Override
180 - public void groupOperationFailed(GroupOperation operation) { 180 + public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
181 this.failedOperation = operation; 181 this.failedOperation = operation;
182 } 182 }
183 183
......