Bc Group population during cluster reboot 05/84505/4
authormanojna v <manojna.vijayakrishna@ericsson.com>
Tue, 17 Sep 2019 09:19:45 +0000 (14:49 +0530)
committermanojna v <manojna.vijayakrishna@ericsson.com>
Fri, 4 Oct 2019 05:40:43 +0000 (11:10 +0530)
these changes make sure that during cluster reboot scenario,
bc groups remain intact as they were before cluster reboot.

as the elan interfaces gets replayed elan broadcast group
gets reconstructed from scratch and as the final elan interface is added
elan broadcast group will become identical to what it was before cluster
reboot.

During this period where bc group starts with 1 bucket and reaches to
the correct no of buckets the broadcast traffic will be affected.

while doing bc group update, instead of replacing the group with new set
of buckets , first read existing buckets and add the new buckets to
existing buckets.

Change-Id: I111a9efa6c354724681ea4e7fc76cb6f37ba7f1e
Signed-off-by: manojna v <manojna.vijayakrishna@ericsson.com>
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanDpnInterfaceClusteredListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanExtnTepListener.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/BcGroupUpdateJob.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanConstants.java
elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java

index be789534d1cf797b3d16ff5bd6789e9792b8a3e0..f2bca580efa91899721edf82bf20c77e5b77e74a 100644 (file)
@@ -126,7 +126,7 @@ public class ElanDpnInterfaceClusteredListener
                     McastUpdateJob.updateAllMcastsForDpnDelete(elanName, elanL2GatewayMulticastUtils,
                             elanClusterUtils, dpnInterfaces.getDpId(), elanItmUtils);
                     BcGroupUpdateJob.updateAllBcGroups(elanName, elanRefUtil, elanL2GatewayMulticastUtils,
-                            broker);
+                            broker, false);
                 }
             } finally {
                 elanInstanceDpnsCache.remove(getElanName(identifier), dpnInterfaces);
@@ -161,7 +161,7 @@ public class ElanDpnInterfaceClusteredListener
                 ElanInstance elanInstance = elanInstanceCache.get(elanName).orNull();
                 if (elanInstance != null) {
                     BcGroupUpdateJob.updateAllBcGroups(elanName, elanRefUtil, elanL2GatewayMulticastUtils,
-                            broker);
+                            broker, true);
                     // updating remote mcast mac on l2gw devices
                     McastUpdateJob.updateAllMcastsForDpnAdd(elanName, elanL2GatewayMulticastUtils,
                             elanClusterUtils);
index af8fec506833520766ff86ce20d0cf7e24e08fad..4ad8848badaf359e8b3a1d1154bd8c6cbb1f832f 100644 (file)
@@ -64,7 +64,7 @@ public class ElanExtnTepListener extends AsyncClusteredDataTreeChangeListenerBas
     @Override
     protected void add(InstanceIdentifier<ExternalTeps> instanceIdentifier, ExternalTeps tep) {
         LOG.trace("ExternalTeps add received {}", instanceIdentifier);
-        updateBcGroupOfElan(instanceIdentifier, tep);
+        updateBcGroupOfElan(instanceIdentifier, tep, true);
     }
 
     @Override
@@ -74,12 +74,13 @@ public class ElanExtnTepListener extends AsyncClusteredDataTreeChangeListenerBas
     @Override
     protected void remove(InstanceIdentifier<ExternalTeps> instanceIdentifier, ExternalTeps tep) {
         LOG.trace("ExternalTeps remove received {}", instanceIdentifier);
-        updateBcGroupOfElan(instanceIdentifier, tep);
+        updateBcGroupOfElan(instanceIdentifier, tep, false);
     }
 
-    protected void updateBcGroupOfElan(InstanceIdentifier<ExternalTeps> instanceIdentifier, ExternalTeps tep) {
+    protected void updateBcGroupOfElan(InstanceIdentifier<ExternalTeps> instanceIdentifier, ExternalTeps tep,
+                                       boolean add) {
         String elanName = instanceIdentifier.firstKeyOf(ElanInstance.class).getElanInstanceName();
-        BcGroupUpdateJob.updateAllBcGroups(elanName, elanRefUtil, elanL2GatewayMulticastUtils, broker);
+        BcGroupUpdateJob.updateAllBcGroups(elanName, elanRefUtil, elanL2GatewayMulticastUtils, broker, add);
     }
 
     @Override
index 88a8078ea868295c187a223682836a8967cc10dd..48c13ffcc9eb013b2445b9a44afebda9714eae31 100644 (file)
@@ -35,16 +35,18 @@ public class BcGroupUpdateJob implements Callable<List<ListenableFuture<Void>>>
     private final ElanRefUtil elanRefUtil;
     private final ManagedNewTransactionRunner txRunner;
     protected String jobKey;
+    private final boolean createCase;
 
     public BcGroupUpdateJob(String elanName,
                             ElanRefUtil elanRefUtil,
                             ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
-                            DataBroker dataBroker) {
+                            DataBroker dataBroker, boolean createCase) {
         this.jobKey = ElanUtils.getBcGroupUpdateKey(elanName);
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.elanName = elanName;
         this.elanRefUtil = elanRefUtil;
         this.elanL2GatewayMulticastUtils = elanL2GatewayMulticastUtils;
+        this.createCase = createCase;
     }
 
     public void submit() {
@@ -57,7 +59,7 @@ public class BcGroupUpdateJob implements Callable<List<ListenableFuture<Void>>>
         if (elanInstanceOptional.isPresent()) {
             return Lists.newArrayList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
                 confTx -> elanL2GatewayMulticastUtils.updateRemoteBroadcastGroupForAllElanDpns(
-                        elanInstanceOptional.get(), confTx)));
+                        elanInstanceOptional.get(), createCase, confTx)));
         }
         return null;
     }
@@ -65,7 +67,7 @@ public class BcGroupUpdateJob implements Callable<List<ListenableFuture<Void>>>
     public static void updateAllBcGroups(String elanName,
                                          ElanRefUtil elanRefUtil,
                                          ElanL2GatewayMulticastUtils elanL2GatewayMulticastUtils,
-                                         DataBroker dataBroker) {
-        new BcGroupUpdateJob(elanName, elanRefUtil, elanL2GatewayMulticastUtils, dataBroker).submit();
+                                         DataBroker dataBroker, boolean createCase) {
+        new BcGroupUpdateJob(elanName, elanRefUtil, elanL2GatewayMulticastUtils, dataBroker, createCase).submit();
     }
 }
index 5a0067ec51ebb32bdee82739451f9609bc0a705d..82bc998e8a576ebe59c078877e27460ba131d38a 100644 (file)
@@ -250,11 +250,11 @@ public class ElanL2GatewayMulticastUtils {
         }
     }
 
-    public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo,
+    public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, boolean createCase,
             TypedWriteTransaction<Datastore.Configuration> confTx) {
         List<DpnInterfaces> dpns = elanUtils.getInvolvedDpnsInElan(elanInfo.getElanInstanceName());
         for (DpnInterfaces dpn : dpns) {
-            setupElanBroadcastGroups(elanInfo, dpn.getDpId(), confTx);
+            setupStandardElanBroadcastGroups(elanInfo, null, dpn.getDpId(), createCase, confTx);
         }
     }
 
@@ -264,13 +264,18 @@ public class ElanL2GatewayMulticastUtils {
     }
 
     public void setupElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, BigInteger dpnId,
-            TypedWriteTransaction<Datastore.Configuration> confTx) {
+                                         TypedWriteTransaction<Datastore.Configuration> confTx) {
         setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
         setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx);
     }
 
+    public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId,
+                                                 TypedWriteTransaction<Datastore.Configuration> confTx) {
+        setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, true, confTx);
+    }
+
     public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
-            BigInteger dpnId, TypedWriteTransaction<Datastore.Configuration> confTx) {
+            BigInteger dpnId, boolean createCase, TypedWriteTransaction<Datastore.Configuration> confTx) {
         List<Bucket> listBucket = new ArrayList<>();
         int bucketId = 0;
         int actionKey = 0;
@@ -286,7 +291,11 @@ public class ElanL2GatewayMulticastUtils {
         Group group = MDSALUtil.buildGroup(groupId, elanInfo.getElanInstanceName(), GroupTypes.GroupAll,
                 MDSALUtil.buildBucketLists(listBucket));
         LOG.trace("Installing the remote BroadCast Group:{}", group);
-        mdsalManager.addGroup(confTx, dpnId, group);
+        if (createCase) {
+            elanUtils.syncUpdateGroup(dpnId, group, ElanConstants.DELAY_TIME_IN_MILLISECOND, confTx);
+        } else {
+            mdsalManager.addGroup(confTx, dpnId, group);
+        }
     }
 
     public void setupLeavesEtreeBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces,
index f933e62aa8c2fda927be5a1ad4cb006ab8c656d1..ad8aceb4b2c64c3e5c78cd4c3b7cef25db553816 100755 (executable)
@@ -20,6 +20,7 @@ public interface ElanConstants {
     String ELAN_ID_POOL_NAME = "elan.ids.pool";
     long ELAN_ID_LOW_VALUE = 5000L;
     long ELAN_ID_HIGH_VALUE = 10000L;
+    long DELAY_TIME_IN_MILLISECOND = 5000;
     int ELAN_GID_MIN = 200000;
     int ELAN_SERVICE_PRIORITY = 5;
     int STATIC_MAC_TIMEOUT = 0;
index c896d0cfb15304ca9884aec7a0f5d70ed43cb8f4..88d29f9ee514c11d7bd10afc1c96849fe4e50eb8 100755 (executable)
@@ -26,10 +26,16 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.apache.commons.lang3.StringUtils;
@@ -78,6 +84,7 @@ import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
 import org.opendaylight.netvirt.elan.arp.responder.ArpResponderUtil;
 import org.opendaylight.netvirt.elan.cache.ElanInterfaceCache;
+import org.opendaylight.netvirt.elan.internal.ElanGroupCache;
 import org.opendaylight.netvirt.elanmanager.api.ElanHelper;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
@@ -129,7 +136,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.I
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveTerminatingServiceActionsOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
@@ -234,6 +246,16 @@ public class ElanUtils {
     private final ElanEtreeUtils elanEtreeUtils;
     private final ElanInterfaceCache elanInterfaceCache;
     private final IITMProvider iitmProvider;
+    private final ElanGroupCache elanGroupCache;
+
+    private static final Function<Bucket, Bucket> TO_BUCKET_WITHOUT_ID = (bucket) -> new BucketBuilder(bucket)
+            .setBucketId(new BucketId(0L))
+            .build();
+
+    private static final BiFunction<Bucket, AtomicLong, Bucket> TO_BUCKET_WITH_ID = (bucket, id)
+        -> new BucketBuilder(bucket)
+            .setBucketId(new BucketId(id.incrementAndGet()))
+            .build();
 
     public static final FutureCallback<Void> DEFAULT_CALLBACK = new FutureCallback<Void>() {
         @Override
@@ -251,7 +273,7 @@ public class ElanUtils {
     public ElanUtils(DataBroker dataBroker, IMdsalApiManager mdsalManager,
             OdlInterfaceRpcService interfaceManagerRpcService, ItmRpcService itmRpcService, ElanConfig elanConfig,
             IInterfaceManager interfaceManager, ElanEtreeUtils elanEtreeUtils, ElanItmUtils elanItmUtils,
-            ElanInterfaceCache elanInterfaceCache, IITMProvider iitmProvider) {
+            ElanInterfaceCache elanInterfaceCache, IITMProvider iitmProvider, ElanGroupCache elanGroupCache) {
         this.broker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         this.mdsalManager = mdsalManager;
@@ -263,6 +285,7 @@ public class ElanUtils {
         this.elanItmUtils = elanItmUtils;
         this.elanInterfaceCache = elanInterfaceCache;
         this.iitmProvider = iitmProvider;
+        this.elanGroupCache = elanGroupCache;
     }
 
     public final Boolean isOpenstackVniSemanticsEnforced() {
@@ -1638,6 +1661,71 @@ public class ElanUtils {
         return null;
     }
 
+    protected  Node buildDpnNode(BigInteger dpnId) {
+        org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId nodeId =
+                new org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819
+                        .NodeId("openflow:" + dpnId);
+        Node nodeDpn = new NodeBuilder().setId(nodeId).withKey(new NodeKey(nodeId)).build();
+        return nodeDpn;
+    }
+
+    public void syncUpdateGroup(BigInteger dpnId, Group newGroup, long delayTime,
+                                TypedWriteTransaction<Datastore.Configuration> confTx) {
+        Node nodeDpn = buildDpnNode(dpnId);
+        long groupIdInfo = newGroup.getGroupId().getValue();
+        GroupKey groupKey = new GroupKey(new GroupId(groupIdInfo));
+        InstanceIdentifier<Group> groupInstanceId = InstanceIdentifier.builder(Nodes.class)
+                .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
+                .child(Group.class, groupKey).build();
+        LOG.trace("Performing merge operation for remote BC group for node {} with group {}", nodeDpn, newGroup);
+        Optional<Group> existingGroupOpt = ElanUtils.read(broker, LogicalDatastoreType.CONFIGURATION, groupInstanceId);
+        if (!existingGroupOpt.isPresent()) {
+            LOG.debug("Group {} doesn't exist. Performing syncInstall", groupIdInfo);
+            mdsalManager.addGroup(confTx, dpnId, newGroup);
+            return;
+        }
+        Buckets existingGroup = existingGroupOpt.get().getBuckets();
+        if (existingGroup == null) {
+            LOG.debug("Bucket doesn't exist for group {}. Performing syncInstall", groupIdInfo);
+            mdsalManager.addGroup(confTx, dpnId, newGroup);
+            return;
+        }
+        if (newGroup.getBuckets() == null) {
+            LOG.debug("Buckets are not sent for group {}. Skipping merge operation", groupIdInfo);
+            return;
+        }
+        List<Bucket> newBuckets = newGroup.getBuckets().getBucket();
+        List<Bucket> existingBuckets = existingGroup.getBucket();
+        Set<Bucket> toMergeBucketsWithoutId = new LinkedHashSet<>();
+
+        existingBuckets.stream()
+                .map(TO_BUCKET_WITHOUT_ID)
+                .forEach(bucketWithoutId -> toMergeBucketsWithoutId.add(bucketWithoutId));
+
+        newBuckets.stream()
+                .map(TO_BUCKET_WITHOUT_ID)
+                .forEach(bucketWithoutId -> toMergeBucketsWithoutId.add(bucketWithoutId));
+
+        if (toMergeBucketsWithoutId.size() == existingBuckets.size()) {
+            //no new buckets got added
+            //size matched and no extra buckets in existing buckets , rewrite the group
+            LOG.debug("Buckets did not change group {}. Skipping merge operation", groupIdInfo);
+            return;
+        }
+        LOG.debug("Old group buckets size {} New group buckets size {} Dpn id {} Group id {} ",
+                existingBuckets.size(), toMergeBucketsWithoutId.size(), dpnId, groupIdInfo);
+        AtomicLong bucketIdValue = new AtomicLong(-1);
+        //Change the bucket id of existing buckets
+        List<Bucket> bucketsToBeAdded = toMergeBucketsWithoutId.stream()
+                .map(bucketWithoutId -> TO_BUCKET_WITH_ID.apply(bucketWithoutId, bucketIdValue))
+                .collect(Collectors.toList());
+
+        Group group = MDSALUtil.buildGroup(newGroup.getGroupId().getValue(), newGroup.getGroupName(),
+                GroupTypes.GroupAll, MDSALUtil.buildBucketLists(bucketsToBeAdded));
+        mdsalManager.addGroup(confTx, dpnId, group);
+        LOG.trace("Installed remote BC group for node {} with group {}", nodeDpn, group);
+    }
+
     static InstanceIdentifier<Subnetmaps> buildSubnetMapsWildCardPath() {
         return InstanceIdentifier.create(Subnetmaps.class);
     }