From 8a96fbad4dc8708ad2995137fc293232e48d25e5 Mon Sep 17 00:00:00 2001 From: manojna v Date: Tue, 17 Sep 2019 14:49:45 +0530 Subject: [PATCH] Bc Group population during cluster reboot 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 --- .../ElanDpnInterfaceClusteredListener.java | 4 +- .../elan/internal/ElanExtnTepListener.java | 9 +- .../elan/l2gw/jobs/BcGroupUpdateJob.java | 10 ++- .../utils/ElanL2GatewayMulticastUtils.java | 19 ++-- .../netvirt/elan/utils/ElanConstants.java | 1 + .../netvirt/elan/utils/ElanUtils.java | 90 ++++++++++++++++++- 6 files changed, 117 insertions(+), 16 deletions(-) diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanDpnInterfaceClusteredListener.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanDpnInterfaceClusteredListener.java index be789534d1..f2bca580ef 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanDpnInterfaceClusteredListener.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanDpnInterfaceClusteredListener.java @@ -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); diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanExtnTepListener.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanExtnTepListener.java index af8fec5068..4ad8848bad 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanExtnTepListener.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/internal/ElanExtnTepListener.java @@ -64,7 +64,7 @@ public class ElanExtnTepListener extends AsyncClusteredDataTreeChangeListenerBas @Override protected void add(InstanceIdentifier 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 instanceIdentifier, ExternalTeps tep) { LOG.trace("ExternalTeps remove received {}", instanceIdentifier); - updateBcGroupOfElan(instanceIdentifier, tep); + updateBcGroupOfElan(instanceIdentifier, tep, false); } - protected void updateBcGroupOfElan(InstanceIdentifier instanceIdentifier, ExternalTeps tep) { + protected void updateBcGroupOfElan(InstanceIdentifier 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 diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/BcGroupUpdateJob.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/BcGroupUpdateJob.java index 88a8078ea8..48c13ffcc9 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/BcGroupUpdateJob.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/jobs/BcGroupUpdateJob.java @@ -35,16 +35,18 @@ public class BcGroupUpdateJob implements Callable>> 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>> 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>> 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(); } } diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java index 5a0067ec51..82bc998e8a 100644 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/l2gw/utils/ElanL2GatewayMulticastUtils.java @@ -250,11 +250,11 @@ public class ElanL2GatewayMulticastUtils { } } - public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, + public void updateRemoteBroadcastGroupForAllElanDpns(ElanInstance elanInfo, boolean createCase, TypedWriteTransaction confTx) { List 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 confTx) { + TypedWriteTransaction confTx) { setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx); setupLeavesEtreeBroadcastGroups(elanInfo, dpnInterfaces, dpnId, confTx); } + public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, DpnInterfaces dpnInterfaces, BigInteger dpnId, + TypedWriteTransaction confTx) { + setupStandardElanBroadcastGroups(elanInfo, dpnInterfaces, dpnId, true, confTx); + } + public void setupStandardElanBroadcastGroups(ElanInstance elanInfo, @Nullable DpnInterfaces dpnInterfaces, - BigInteger dpnId, TypedWriteTransaction confTx) { + BigInteger dpnId, boolean createCase, TypedWriteTransaction confTx) { List 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, diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanConstants.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanConstants.java index f933e62aa8..ad8aceb4b2 100755 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanConstants.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanConstants.java @@ -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; diff --git a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java index c896d0cfb1..88d29f9ee5 100755 --- a/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java +++ b/elanmanager/impl/src/main/java/org/opendaylight/netvirt/elan/utils/ElanUtils.java @@ -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 TO_BUCKET_WITHOUT_ID = (bucket) -> new BucketBuilder(bucket) + .setBucketId(new BucketId(0L)) + .build(); + + private static final BiFunction TO_BUCKET_WITH_ID = (bucket, id) + -> new BucketBuilder(bucket) + .setBucketId(new BucketId(id.incrementAndGet())) + .build(); public static final FutureCallback DEFAULT_CALLBACK = new FutureCallback() { @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 confTx) { + Node nodeDpn = buildDpnNode(dpnId); + long groupIdInfo = newGroup.getGroupId().getValue(); + GroupKey groupKey = new GroupKey(new GroupId(groupIdInfo)); + InstanceIdentifier 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 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 newBuckets = newGroup.getBuckets().getBucket(); + List existingBuckets = existingGroup.getBucket(); + Set 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 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 buildSubnetMapsWildCardPath() { return InstanceIdentifier.create(Subnetmaps.class); } -- 2.36.6