Victor Silva
Committed by Gerrit Code Review

[ONOS-5169] GroupStore: properly add updated buckets

Adding buckets to group was ignoring the addition of groups
with different weights because they had the same treatment
and type. We'll now update such groupbuckets with the desired new
parameters.

Change-Id: I5f102c5fd78912844883c897bd858ee282f3cc12
...@@ -235,6 +235,13 @@ public final class DefaultGroupBucket implements GroupBucket, StoredGroupBucketE ...@@ -235,6 +235,13 @@ public final class DefaultGroupBucket implements GroupBucket, StoredGroupBucketE
235 } 235 }
236 236
237 @Override 237 @Override
238 + public boolean hasSameParameters(GroupBucket other) {
239 + return weight == other.weight() &&
240 + Objects.equals(watchPort, other.watchPort()) &&
241 + Objects.equals(watchGroup, other.watchGroup());
242 + }
243 +
244 + @Override
238 public String toString() { 245 public String toString() {
239 return toStringHelper(this) 246 return toStringHelper(this)
240 .add("type", type) 247 .add("type", type)
......
...@@ -77,4 +77,12 @@ public interface GroupBucket { ...@@ -77,4 +77,12 @@ public interface GroupBucket {
77 * @return number of bytes 77 * @return number of bytes
78 */ 78 */
79 long bytes(); 79 long bytes();
80 +
81 + /**
82 + * Returns whether the given GroupBucket has the same parameters (weight,
83 + * watchPort and watchGroup) as this.
84 + *
85 + * @param other GroupBucket to compare
86 + */
87 + boolean hasSameParameters(GroupBucket other);
80 } 88 }
......
...@@ -321,32 +321,50 @@ public class SimpleGroupStore ...@@ -321,32 +321,50 @@ public class SimpleGroupStore
321 private List<GroupBucket> getUpdatedBucketList(Group oldGroup, 321 private List<GroupBucket> getUpdatedBucketList(Group oldGroup,
322 UpdateType type, 322 UpdateType type,
323 GroupBuckets buckets) { 323 GroupBuckets buckets) {
324 - GroupBuckets oldBuckets = oldGroup.buckets(); 324 + List<GroupBucket> oldBuckets = oldGroup.buckets().buckets();
325 - List<GroupBucket> newBucketList = new ArrayList<>(oldBuckets.buckets()); 325 + List<GroupBucket> updatedBucketList = new ArrayList<>();
326 boolean groupDescUpdated = false; 326 boolean groupDescUpdated = false;
327 327
328 if (type == UpdateType.ADD) { 328 if (type == UpdateType.ADD) {
329 - // Check if the any of the new buckets are part of 329 + List<GroupBucket> newBuckets = buckets.buckets();
330 - // the old bucket list 330 +
331 - for (GroupBucket addBucket:buckets.buckets()) { 331 + // Add old buckets that will not be updated and check if any will be updated.
332 - if (!newBucketList.contains(addBucket)) { 332 + for (GroupBucket oldBucket : oldBuckets) {
333 - newBucketList.add(addBucket); 333 + int newBucketIndex = newBuckets.indexOf(oldBucket);
334 +
335 + if (newBucketIndex != -1) {
336 + GroupBucket newBucket = newBuckets.get(newBucketIndex);
337 + if (!newBucket.hasSameParameters(oldBucket)) {
338 + // Bucket will be updated
334 groupDescUpdated = true; 339 groupDescUpdated = true;
335 } 340 }
341 + } else {
342 + // Old bucket will remain the same - add it.
343 + updatedBucketList.add(oldBucket);
344 + }
345 + }
346 +
347 + // Add all new buckets
348 + updatedBucketList.addAll(newBuckets);
349 + if (!oldBuckets.containsAll(newBuckets)) {
350 + groupDescUpdated = true;
336 } 351 }
352 +
337 } else if (type == UpdateType.REMOVE) { 353 } else if (type == UpdateType.REMOVE) {
338 - // Check if the to be removed buckets are part of the 354 + List<GroupBucket> bucketsToRemove = buckets.buckets();
339 - // old bucket list 355 +
340 - for (GroupBucket removeBucket:buckets.buckets()) { 356 + // Check which old buckets should remain
341 - if (newBucketList.contains(removeBucket)) { 357 + for (GroupBucket oldBucket : oldBuckets) {
342 - newBucketList.remove(removeBucket); 358 + if (!bucketsToRemove.contains(oldBucket)) {
359 + updatedBucketList.add(oldBucket);
360 + } else {
343 groupDescUpdated = true; 361 groupDescUpdated = true;
344 } 362 }
345 } 363 }
346 } 364 }
347 365
348 if (groupDescUpdated) { 366 if (groupDescUpdated) {
349 - return newBucketList; 367 + return updatedBucketList;
350 } else { 368 } else {
351 return null; 369 return null;
352 } 370 }
......
...@@ -130,6 +130,18 @@ public class SimpleGroupStoreTest { ...@@ -130,6 +130,18 @@ public class SimpleGroupStoreTest {
130 } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_REQUESTED) { 130 } else if (expectedEvent == GroupEvent.Type.GROUP_UPDATE_REQUESTED) {
131 assertEquals(Group.GroupState.PENDING_UPDATE, 131 assertEquals(Group.GroupState.PENDING_UPDATE,
132 event.subject().state()); 132 event.subject().state());
133 + for (GroupBucket bucket:event.subject().buckets().buckets()) {
134 + Optional<GroupBucket> matched = createdBuckets.buckets()
135 + .stream()
136 + .filter((expected) -> expected.equals(bucket))
137 + .findFirst();
138 + assertEquals(matched.get().weight(),
139 + bucket.weight());
140 + assertEquals(matched.get().watchGroup(),
141 + bucket.watchGroup());
142 + assertEquals(matched.get().watchPort(),
143 + bucket.watchPort());
144 + }
133 } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_REQUESTED) { 145 } else if (expectedEvent == GroupEvent.Type.GROUP_REMOVE_REQUESTED) {
134 assertEquals(Group.GroupState.PENDING_DELETE, 146 assertEquals(Group.GroupState.PENDING_DELETE,
135 event.subject().state()); 147 event.subject().state());
...@@ -342,6 +354,36 @@ public class SimpleGroupStoreTest { ...@@ -342,6 +354,36 @@ public class SimpleGroupStoreTest {
342 toAddGroupBuckets, 354 toAddGroupBuckets,
343 addKey); 355 addKey);
344 simpleGroupStore.unsetDelegate(updateGroupDescDelegate); 356 simpleGroupStore.unsetDelegate(updateGroupDescDelegate);
357 +
358 + short weight = 5;
359 + toAddBuckets = new ArrayList<>();
360 + for (PortNumber portNumber: newOutPorts) {
361 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
362 + tBuilder.setOutput(portNumber)
363 + .setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
364 + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01"))
365 + .pushMpls()
366 + .setMpls(MplsLabel.mplsLabel(106));
367 + toAddBuckets.add(DefaultGroupBucket.createSelectGroupBucket(
368 + tBuilder.build(), weight));
369 + }
370 +
371 + toAddGroupBuckets = new GroupBuckets(toAddBuckets);
372 + buckets = new ArrayList<>();
373 + buckets.addAll(existingGroup.buckets().buckets());
374 + buckets.addAll(toAddBuckets);
375 + updatedGroupBuckets = new GroupBuckets(buckets);
376 + updateGroupDescDelegate =
377 + new InternalGroupStoreDelegate(addKey,
378 + updatedGroupBuckets,
379 + GroupEvent.Type.GROUP_UPDATE_REQUESTED);
380 + simpleGroupStore.setDelegate(updateGroupDescDelegate);
381 + simpleGroupStore.updateGroupDescription(D1,
382 + addKey,
383 + UpdateType.ADD,
384 + toAddGroupBuckets,
385 + addKey);
386 + simpleGroupStore.unsetDelegate(updateGroupDescDelegate);
345 } 387 }
346 388
347 // Testing updateGroupDescription for REMOVE operation from northbound 389 // Testing updateGroupDescription for REMOVE operation from northbound
......
...@@ -719,32 +719,50 @@ public class DistributedGroupStore ...@@ -719,32 +719,50 @@ public class DistributedGroupStore
719 private List<GroupBucket> getUpdatedBucketList(Group oldGroup, 719 private List<GroupBucket> getUpdatedBucketList(Group oldGroup,
720 UpdateType type, 720 UpdateType type,
721 GroupBuckets buckets) { 721 GroupBuckets buckets) {
722 - GroupBuckets oldBuckets = oldGroup.buckets(); 722 + List<GroupBucket> oldBuckets = oldGroup.buckets().buckets();
723 - List<GroupBucket> newBucketList = new ArrayList<>(oldBuckets.buckets()); 723 + List<GroupBucket> updatedBucketList = new ArrayList<>();
724 boolean groupDescUpdated = false; 724 boolean groupDescUpdated = false;
725 725
726 if (type == UpdateType.ADD) { 726 if (type == UpdateType.ADD) {
727 - // Check if the any of the new buckets are part of 727 + List<GroupBucket> newBuckets = buckets.buckets();
728 - // the old bucket list 728 +
729 - for (GroupBucket addBucket : buckets.buckets()) { 729 + // Add old buckets that will not be updated and check if any will be updated.
730 - if (!newBucketList.contains(addBucket)) { 730 + for (GroupBucket oldBucket : oldBuckets) {
731 - newBucketList.add(addBucket); 731 + int newBucketIndex = newBuckets.indexOf(oldBucket);
732 +
733 + if (newBucketIndex != -1) {
734 + GroupBucket newBucket = newBuckets.get(newBucketIndex);
735 + if (!newBucket.hasSameParameters(oldBucket)) {
736 + // Bucket will be updated
732 groupDescUpdated = true; 737 groupDescUpdated = true;
733 } 738 }
739 + } else {
740 + // Old bucket will remain the same - add it.
741 + updatedBucketList.add(oldBucket);
742 + }
743 + }
744 +
745 + // Add all new buckets
746 + updatedBucketList.addAll(newBuckets);
747 + if (!oldBuckets.containsAll(newBuckets)) {
748 + groupDescUpdated = true;
734 } 749 }
750 +
735 } else if (type == UpdateType.REMOVE) { 751 } else if (type == UpdateType.REMOVE) {
736 - // Check if the to be removed buckets are part of the 752 + List<GroupBucket> bucketsToRemove = buckets.buckets();
737 - // old bucket list 753 +
738 - for (GroupBucket removeBucket : buckets.buckets()) { 754 + // Check which old buckets should remain
739 - if (newBucketList.contains(removeBucket)) { 755 + for (GroupBucket oldBucket : oldBuckets) {
740 - newBucketList.remove(removeBucket); 756 + if (!bucketsToRemove.contains(oldBucket)) {
757 + updatedBucketList.add(oldBucket);
758 + } else {
741 groupDescUpdated = true; 759 groupDescUpdated = true;
742 } 760 }
743 } 761 }
744 } 762 }
745 763
746 if (groupDescUpdated) { 764 if (groupDescUpdated) {
747 - return newBucketList; 765 + return updatedBucketList;
748 } else { 766 } else {
749 return null; 767 return null;
750 } 768 }
......
...@@ -60,6 +60,7 @@ import static org.hamcrest.Matchers.instanceOf; ...@@ -60,6 +60,7 @@ import static org.hamcrest.Matchers.instanceOf;
60 import static org.hamcrest.Matchers.is; 60 import static org.hamcrest.Matchers.is;
61 import static org.hamcrest.Matchers.notNullValue; 61 import static org.hamcrest.Matchers.notNullValue;
62 import static org.hamcrest.Matchers.nullValue; 62 import static org.hamcrest.Matchers.nullValue;
63 +import static org.junit.Assert.assertEquals;
63 import static org.onosproject.net.NetTestTools.APP_ID; 64 import static org.onosproject.net.NetTestTools.APP_ID;
64 import static org.onosproject.net.NetTestTools.did; 65 import static org.onosproject.net.NetTestTools.did;
65 import static org.onosproject.net.group.GroupDescription.Type.*; 66 import static org.onosproject.net.group.GroupDescription.Type.*;
...@@ -390,7 +391,7 @@ public class DistributedGroupStoreTest { ...@@ -390,7 +391,7 @@ public class DistributedGroupStoreTest {
390 public void testUpdateGroupDescription() { 391 public void testUpdateGroupDescription() {
391 392
392 GroupBuckets buckets = 393 GroupBuckets buckets =
393 - new GroupBuckets(ImmutableList.of(failoverGroupBucket)); 394 + new GroupBuckets(ImmutableList.of(failoverGroupBucket, selectGroupBucket));
394 395
395 groupStore.deviceInitialAuditCompleted(deviceId1, true); 396 groupStore.deviceInitialAuditCompleted(deviceId1, true);
396 groupStore.storeGroupDescription(groupDescription1); 397 groupStore.storeGroupDescription(groupDescription1);
...@@ -404,6 +405,27 @@ public class DistributedGroupStoreTest { ...@@ -404,6 +405,27 @@ public class DistributedGroupStoreTest {
404 Group group1 = groupStore.getGroup(deviceId1, groupId1); 405 Group group1 = groupStore.getGroup(deviceId1, groupId1);
405 assertThat(group1.appCookie(), is(newKey)); 406 assertThat(group1.appCookie(), is(newKey));
406 assertThat(group1.buckets().buckets(), hasSize(2)); 407 assertThat(group1.buckets().buckets(), hasSize(2));
408 +
409 + short weight = 5;
410 + GroupBucket selectGroupBucketWithWeight =
411 + DefaultGroupBucket.createSelectGroupBucket(treatment, weight);
412 + buckets = new GroupBuckets(ImmutableList.of(failoverGroupBucket,
413 + selectGroupBucketWithWeight));
414 +
415 + groupStore.updateGroupDescription(deviceId1,
416 + newKey,
417 + ADD,
418 + buckets,
419 + newKey);
420 +
421 + group1 = groupStore.getGroup(deviceId1, groupId1);
422 + assertThat(group1.appCookie(), is(newKey));
423 + assertThat(group1.buckets().buckets(), hasSize(2));
424 + for (GroupBucket bucket : group1.buckets().buckets()) {
425 + if (bucket.type() == SELECT) {
426 + assertEquals(weight, bucket.weight());
427 + }
428 + }
407 } 429 }
408 430
409 @Test 431 @Test
......