X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=fibmanager%2Fimpl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fnetvirt%2Ffibmanager%2FVrfEntryListener.java;h=540e06aaf55e551cd6bfc4fefd449829333c1181;hb=bf9dcb80a0dfd9c5f83a9d8fd8044e7d74f606cf;hp=5d66993cf831a99135107f240a000fe3248eb28d;hpb=8197d6cf5954e190ce70c1721d80acd0b8c2e3ca;p=netvirt.git diff --git a/fibmanager/impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java b/fibmanager/impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java old mode 100755 new mode 100644 index 5d66993cf8..540e06aaf5 --- a/fibmanager/impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java +++ b/fibmanager/impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java @@ -7,10 +7,14 @@ */ package org.opendaylight.netvirt.fibmanager; +import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS; +import static org.opendaylight.genius.infra.Datastore.CONFIGURATION; +import static org.opendaylight.genius.infra.Datastore.OPERATIONAL; import static org.opendaylight.genius.mdsalutil.NWUtil.isIpv4Address; import com.google.common.base.Optional; import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -24,21 +28,28 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.ReentrantLock; +import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.inject.Inject; import javax.inject.Singleton; +import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.controller.md.sal.binding.api.DataBroker; -import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException; import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase; import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar; +import org.opendaylight.genius.infra.Datastore.Configuration; +import org.opendaylight.genius.infra.Datastore.Operational; import org.opendaylight.genius.infra.ManagedNewTransactionRunner; import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl; import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner; +import org.opendaylight.genius.infra.TransactionAdapter; +import org.opendaylight.genius.infra.TypedReadWriteTransaction; +import org.opendaylight.genius.infra.TypedWriteTransaction; import org.opendaylight.genius.mdsalutil.ActionInfo; import org.opendaylight.genius.mdsalutil.FlowEntity; import org.opendaylight.genius.mdsalutil.InstructionInfo; @@ -47,7 +58,6 @@ import org.opendaylight.genius.mdsalutil.MatchInfo; import org.opendaylight.genius.mdsalutil.MetaDataUtil; import org.opendaylight.genius.mdsalutil.NWUtil; import org.opendaylight.genius.mdsalutil.NwConstants; -import org.opendaylight.genius.mdsalutil.UpgradeState; import org.opendaylight.genius.mdsalutil.actions.ActionDrop; import org.opendaylight.genius.mdsalutil.actions.ActionGroup; import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls; @@ -60,6 +70,7 @@ import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination; import org.opendaylight.genius.mdsalutil.matches.MatchMetadata; import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel; import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId; +import org.opendaylight.genius.utils.JvmGlobalLocks; import org.opendaylight.genius.utils.ServiceIndex; import org.opendaylight.genius.utils.batching.SubTransaction; import org.opendaylight.infrautils.jobcoordinator.JobCoordinator; @@ -72,6 +83,7 @@ import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper; import org.opendaylight.netvirt.vpnmanager.api.VpnHelper; import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache; import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite; +import org.opendaylight.serviceutils.upgrade.UpgradeState; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId; @@ -219,7 +231,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase nextHopsRemoved = FibHelper.getNextHopListFromRoutePaths(original); nextHopsRemoved.removeAll(FibHelper.getNextHopListFromRoutePaths(update)); - ListenableFuture future = - txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> nextHopsRemoved.parallelStream() - .forEach(nextHopRemoved -> fibUtil.updateUsedRdAndVpnToExtraRoute( - tx, nextHopRemoved, rd, update.getDestPrefix()))); - Futures.addCallback(future, new FutureCallback() { + List> futures = new ArrayList<>(); + ListenableFuture configFuture = + txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, configTx -> + futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> + nextHopsRemoved.parallelStream() + .forEach(nextHopRemoved -> { + try { + fibUtil.updateUsedRdAndVpnToExtraRoute( + configTx, operTx, nextHopRemoved, rd, update.getDestPrefix()); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + })))); + futures.add(configFuture); + Futures.addCallback(configFuture, new FutureCallback() { @Override public void onSuccess(Void result) { createFibEntries(identifier, update); @@ -389,15 +411,16 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { - for (final VpnToDpnList curDpn : vpnToDpnList) { - if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) { - installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx); - installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnId.longValue(), + () -> Collections.singletonList( + txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { + for (final VpnToDpnList curDpn : vpnToDpnList) { + if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) { + installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId, vrfEntry, tx); + installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnId.longValue(), vrfEntry, NwConstants.ADD_FLOW, tx); + } } - } - }))); + }))); } return; } @@ -413,15 +436,18 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry, etherType); if (!localDpnIdList.isEmpty() && vpnToDpnList != null) { jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()), - () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { - synchronized (vpnInstance.getVpnInstanceName().intern()) { + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { + final ReentrantLock lock = lockFor(vpnInstance); + lock.lock(); + try { for (VpnToDpnList vpnDpn : vpnToDpnList) { if (!localDpnIdList.contains(vpnDpn.getDpnId())) { if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) { try { if (RouteOrigin.BGP.getValue().equals(vrfEntry.getOrigin())) { bgpRouteVrfEntryHandler.createRemoteFibEntry(vpnDpn.getDpnId(), - vpnId, vrfTableKey.getRouteDistinguisher(), vrfEntry, tx, + vpnId, vrfTableKey.getRouteDistinguisher(), vrfEntry, + TransactionAdapter.toWriteTransaction(tx), txnObjects); } else { createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), @@ -434,6 +460,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnInstanceNames = lri.getVpnInstanceList(); + List vpnInstanceNames = + lri.getVpnInstanceList() != null ? new ArrayList<>(lri.getVpnInstanceList()) : new ArrayList<>(); vpnInstanceNames.add(vpnInstanceName); builder.setVpnInstanceList(vpnInstanceNames); MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriId, builder.build()); @@ -489,9 +518,9 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) { if (tx == null) { - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit( + ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, newTx -> installSubnetRouteInFib(dpnId, elanTag, rd, vpnId, vrfEntry, newTx)), LOG, "Error installing subnet route in FIB"); return; @@ -505,8 +534,11 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase { List nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry); - synchronized (label.toString().intern()) { - LabelRouteInfo lri = getLabelRouteInfo(label); + final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label); + final ReentrantLock lock = lockFor(lriKey); + lock.lock(); + try { + LabelRouteInfo lri = getLabelRouteInfo(lriKey); if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) { if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) { @@ -522,6 +554,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase instructions = new ArrayList<>(); @@ -530,7 +564,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) { List matches = new ArrayList<>(); LOG.debug("SUBNETROUTE: installSubnetBroadcastAddrDropRule: destPrefix {} rd {} vpnId {} dpnId {}", @@ -598,9 +632,9 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, localNextHopIP); - List vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, - vpnName, usedRds, localNextHopIP); - if (LOG.isDebugEnabled()) { - LOG.debug("Creating Local fib entry with vpnName {} usedRds {} localNextHopIP {} vpnExtraRoutes {}", - vpnName, usedRds, localNextHopIP, vpnExtraRoutes); - } boolean localNextHopSeen = false; - //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn - for (Routes vpnExtraRoute : vpnExtraRoutes) { - String ipPrefix; - if (isIpv4Address(vpnExtraRoute.getNexthopIpList().get(0))) { - ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX; - } else { - ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX; + List vpnExtraRoutes = null; + //Synchronized to prevent missing bucket action due to race condition between refreshFib and + // add/updateFib threads on missing nexthop in VpnToExtraroutes + // FIXME: use an Identifier structure? + final ReentrantLock lock = JvmGlobalLocks.getLockForString(localNextHopIP + FibConstants.SEPARATOR + rd); + lock.lock(); + try { + List usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, localNextHopIP); + vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, + vpnName, usedRds, localNextHopIP); + if (LOG.isDebugEnabled()) { + LOG.debug("Creating Local fib entry with vpnName {} usedRds {} localNextHopIP {} vpnExtraRoutes {}", + vpnName, usedRds, localNextHopIP, vpnExtraRoutes); } - Prefixes localNextHopInfoLocal = fibUtil.getPrefixToInterface(vpnId, - ipPrefix); - if (localNextHopInfoLocal != null) { - localNextHopSeen = true; - BigInteger dpnId = - checkCreateLocalFibEntry(localNextHopInfoLocal, localNextHopInfoLocal.getIpAddress(), - vpnId, rd, vrfEntry, vpnExtraRoute, vpnExtraRoutes, etherType); - returnLocalDpnId.add(dpnId); + + //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn + for (Routes vpnExtraRoute : vpnExtraRoutes) { + String ipPrefix; + if (isIpv4Address(vpnExtraRoute.getNexthopIpList().get(0))) { + ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV4PREFIX; + } else { + ipPrefix = vpnExtraRoute.getNexthopIpList().get(0) + NwConstants.IPV6PREFIX; + } + Prefixes localNextHopInfoLocal = fibUtil.getPrefixToInterface(vpnId, + ipPrefix); + if (localNextHopInfoLocal != null) { + localNextHopSeen = true; + BigInteger dpnId = + checkCreateLocalFibEntry(localNextHopInfoLocal, localNextHopInfoLocal.getIpAddress(), + vpnId, rd, vrfEntry, vpnExtraRoute, vpnExtraRoutes, etherType); + returnLocalDpnId.add(dpnId); + } } + } finally { + lock.unlock(); } if (!localNextHopSeen && RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.SELF_IMPORTED) { java.util.Optional optionalLabel = FibUtil.getLabelFromRoutePaths(vrfEntry); if (optionalLabel.isPresent()) { Long label = optionalLabel.get(); List nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry); - synchronized (label.toString().intern()) { - LabelRouteInfo lri = getLabelRouteInfo(label); + final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label); + final ReentrantLock labelLock = lockFor(lriKey); + labelLock.lock(); + try { + LabelRouteInfo lri = getLabelRouteInfo(lriKey); if (isPrefixAndNextHopPresentInLri(localNextHopIP, nextHopAddressList, lri)) { Optional vpnInstanceOpDataEntryOptional = fibUtil.getVpnInstanceOpData(rd); if (vpnInstanceOpDataEntryOptional.isPresent()) { String vpnInstanceName = vpnInstanceOpDataEntryOptional.get().getVpnInstanceName(); - if (lri.getVpnInstanceList().contains(vpnInstanceName)) { + if (lri.getVpnInstanceList() != null && lri.getVpnInstanceList().contains( + vpnInstanceName)) { localNextHopInfo = updateVpnReferencesInLri(lri, vpnInstanceName, true); localNextHopIP = lri.getPrefix(); } else { @@ -795,6 +844,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnExtraRoutes, + @Nullable Routes routes, @Nullable List vpnExtraRoutes, int etherType) { String vpnName = fibUtil.getVpnNameFromId(vpnId); if (localNextHopInfo != null) { @@ -841,21 +892,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase 1) { groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes); - localGroupId = nextHopManager.getLocalNextHopGroup(vpnId, localNextHopIP); - } else if (routes.getNexthopIpList().size() > 1) { - groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes); - localGroupId = groupId; + localGroupId = nextHopManager.getLocalSelectGroup(vpnId, vrfEntry.getDestPrefix()); } else { - groupId = nextHopManager.createLocalNextHop(vpnId, dpnId, interfaceName, localNextHopIP, - prefix, gwMacAddress); + groupId = nextHopManager.createNextHopGroups(vpnId, rd, dpnId, vrfEntry, routes, vpnExtraRoutes); localGroupId = groupId; } } else { @@ -873,16 +916,15 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase lfibinstructions = Collections.singletonList( new InstructionApplyActions( - Arrays.asList(new ActionPopMpls(etherType), new ActionGroup(groupId)))); + Arrays.asList(new ActionPopMpls(etherType), new ActionGroup(localGroupId)))); java.util.Optional optLabel = FibUtil.getLabelFromRoutePaths(vrfEntry); List nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry); String jobKey = FibUtil.getCreateLocalNextHopJobKey(vpnId, dpnId, vrfEntry.getDestPrefix()); - jobCoordinator.enqueueJob(jobKey, () -> { - return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { + jobCoordinator.enqueueJob(jobKey, + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, instructions, - NwConstants.ADD_FLOW, tx, null); - if (!fibUtil.enforceVxlanDatapathSemanticsforInternalRouterVpn(localNextHopInfo.getSubnetId(), - vpnName, rd)) { + NwConstants.ADD_FLOW, TransactionAdapter.toWriteTransaction(tx), null); + if (FibUtil.isBgpVpn(vpnName, rd)) { optLabel.ifPresent(label -> { if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) { LOG.debug( @@ -892,15 +934,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase id = VpnHelper.getVpnToDpnListIdentifier(rd, dpnId); Optional dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id); - if (dpnInVpn.isPresent()) { - return true; - } - return false; + return dpnInVpn.isPresent(); } + @Nullable private LabelRouteInfo getLabelRouteInfo(Long label) { + return getLabelRouteInfo(new LabelRouteInfoKey(label)); + } + + @Nullable + private LabelRouteInfo getLabelRouteInfo(LabelRouteInfoKey label) { InstanceIdentifier lriIid = InstanceIdentifier.builder(LabelRouteMap.class) - .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build(); + .child(LabelRouteInfo.class, label).build(); Optional opResult = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid); if (opResult.isPresent()) { return opResult.get(); @@ -936,7 +972,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) { if (lri == null) { return true; } @@ -954,7 +991,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) { List actionsInfos = Collections.singletonList(new ActionGroup(groupId)); createTerminatingServiceActions(dpId, (int) label, actionsInfos, tx); @@ -978,7 +1015,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase actionsInfos, - WriteTransaction tx) { + TypedWriteTransaction tx) { List mkMatches = new ArrayList<>(); LOG.debug("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", @@ -1006,11 +1043,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) { FlowEntity flowEntity; LOG.debug("remove terminatingServiceActions called with DpnId = {} and label = {}", dpId, label); List mkMatches = new ArrayList<>(); @@ -1027,7 +1063,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, @@ -1062,13 +1098,11 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, - NwConstants.DEL_FLOW, tx, null); - if (!fibUtil.enforceVxlanDatapathSemanticsforInternalRouterVpn(localNextHopInfo.getSubnetId(), - vpnId, rd)) { + NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null); + if (FibUtil.isBgpVpn(vpnName, rd)) { if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) { FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> { makeLFibTableEntry(dpnId, label, null /* instructions */, DEFAULT_FIB_FLOW_PRIORITY, @@ -1151,64 +1184,80 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) { if (tx == null) { - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(newTx -> { - createRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, newTx); - }), LOG, "Error creating remote FIB entry"); + ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + newTx -> createRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, newTx)), LOG, + "Error creating remote FIB entry"); return; } String vpnName = fibUtil.getVpnNameFromId(vpnId); - LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}", - vrfEntry.getDestPrefix(), rd, remoteDpnId); + LOG.debug("createremotefibentry: adding route {} for rd {} on remoteDpnId {}", vrfEntry.getDestPrefix(), rd, + remoteDpnId); - List adjacencyResults = baseVrfEntryHandler.resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd); - if (adjacencyResults.isEmpty()) { - LOG.error("Could not get interface for route-paths: {} in vpn {} on DPN {}", - vrfEntry.getRoutePaths(), rd, remoteDpnId); - LOG.error("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd); + if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.STATIC) { + programRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, tx); return; } - + // Handling static VRF entries List usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix()); - List vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, - vpnName, usedRds, vrfEntry.getDestPrefix()); - // create loadbalancing groups for extra routes only when the extra route is present behind - // multiple VMs - if (!vpnExtraRoutes.isEmpty() && (vpnExtraRoutes.size() > 1 - || vpnExtraRoutes.get(0).getNexthopIpList().size() > 1)) { - List instructions = new ArrayList<>(); - // Obtain the local routes for this particular dpn. - java.util.Optional routes = vpnExtraRoutes - .stream() - .filter(route -> { - Prefixes prefixToInterface = fibUtil.getPrefixToInterface(vpnId, - fibUtil.getIpPrefix(route.getNexthopIpList().get(0))); - if (prefixToInterface == null) { - return false; - } - return remoteDpnId.equals(prefixToInterface.getDpnId()); - }).findFirst(); - long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry, - routes.isPresent() ? routes.get() : null, vpnExtraRoutes); - if (groupId == FibConstants.INVALID_GROUP_ID) { - LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}", - vrfEntry.getDestPrefix(), rd, remoteDpnId.toString()); - return; - } - List actionInfos = - Collections.singletonList(new ActionGroup(groupId)); - instructions.add(new InstructionApplyActions(actionInfos)); - baseVrfEntryHandler.makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, - NwConstants.ADD_FLOW, tx, null); + List vpnExtraRoutes = + VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker, vpnName, usedRds, vrfEntry.getDestPrefix()); + if (!vpnExtraRoutes.isEmpty()) { + programRemoteFibWithLoadBalancingGroups(remoteDpnId, vpnId, rd, vrfEntry, vpnExtraRoutes); } else { - baseVrfEntryHandler.programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults, null); + // Program in case of other static VRF entries like floating IPs + programRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry, tx); } + } + + private void programRemoteFibWithLoadBalancingGroups(final BigInteger remoteDpnId, final long vpnId, String rd, + final VrfEntry vrfEntry, List vpnExtraRoutes) { + // create loadbalancing groups for extra routes only when the extra route is + // present behind multiple VMs + // Obtain the local routes for this particular dpn. + java.util.Optional routes = vpnExtraRoutes.stream().filter(route -> { + Prefixes prefixToInterface = + fibUtil.getPrefixToInterface(vpnId, FibUtil.getIpPrefix(route.getNexthopIpList().get(0))); + if (prefixToInterface == null) { + return false; + } + return remoteDpnId.equals(prefixToInterface.getDpnId()); + }).findFirst(); + long groupId = nextHopManager.createNextHopGroups(vpnId, rd, remoteDpnId, vrfEntry, + routes.isPresent() ? routes.get() : null, vpnExtraRoutes); + if (groupId == FibConstants.INVALID_GROUP_ID) { + LOG.error("Unable to create Group for local prefix {} on rd {} on Node {}", vrfEntry.getDestPrefix(), rd, + remoteDpnId); + return; + } + List actionInfos = Collections.singletonList(new ActionGroup(groupId)); + List instructions = Lists.newArrayList(new InstructionApplyActions(actionInfos)); + String jobKey = FibUtil.getCreateRemoteNextHopJobKey(vpnId, remoteDpnId, vrfEntry.getDestPrefix()); + jobCoordinator.enqueueJob(jobKey, + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(txn -> { + baseVrfEntryHandler.makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, + NwConstants.ADD_FLOW, txn, null); + }))); LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId); } + private void programRemoteFibEntry(final BigInteger remoteDpnId, final long vpnId, String rd, + final VrfEntry vrfEntry, TypedWriteTransaction tx) { + List adjacencyResults = baseVrfEntryHandler.resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd); + if (adjacencyResults.isEmpty()) { + LOG.error("Could not get interface for route-paths: {} in vpn {} on DPN {}", vrfEntry.getRoutePaths(), rd, + remoteDpnId); + LOG.error("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd); + return; + } + baseVrfEntryHandler.programRemoteFib(remoteDpnId, vpnId, vrfEntry, TransactionAdapter.toWriteTransaction(tx), + rd, adjacencyResults, null); + LOG.debug("Successfully programmed FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId); + } + protected void cleanUpOpDataForFib(Long vpnId, String primaryRd, final VrfEntry vrfEntry) { /* Get interface info from prefix to interface mapping; Use the interface info to get the corresponding vpn interface op DS entry, @@ -1224,7 +1273,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix()); String usedRd = usedRds.isEmpty() ? primaryRd : usedRds.get(0); Routes extraRoute = baseVrfEntryHandler.getVpnToExtraroute(vpnId, usedRd, vrfEntry.getDestPrefix()); - if (extraRoute != null) { + if (extraRoute != null && extraRoute.getNexthopIpList() != null) { for (String nextHopIp : extraRoute.getNexthopIpList()) { LOG.debug("NextHop IP for destination {} is {}", vrfEntry.getDestPrefix(), nextHopIp); if (nextHopIp != null) { @@ -1263,7 +1312,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase> call() { // If another renderer(for eg : CSS) needs to be supported, check can be performed here // to call the respective helpers. - return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> { + return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, tx -> { //First Cleanup LabelRouteInfo //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan LOG.debug("cleanupVpnInterfaceWorker: rd {} prefix {}", rd, prefixInfo.getIpAddress()); if (VrfEntry.EncapType.Mplsgre.equals(vrfEntry.getEncapType())) { FibUtil.getLabelFromRoutePaths(vrfEntry).ifPresent(label -> { List nextHopAddressList = FibHelper.getNextHopListFromRoutePaths(vrfEntry); - synchronized (label.toString().intern()) { - LabelRouteInfo lri = getLabelRouteInfo(label); - if (lri != null && lri.getPrefix().equals(vrfEntry.getDestPrefix()) + final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label); + final ReentrantLock lock = lockFor(lriKey); + lock.lock(); + try { + LabelRouteInfo lri = getLabelRouteInfo(lriKey); + if (lri != null && Objects.equals(lri.getPrefix(), vrfEntry.getDestPrefix()) && nextHopAddressList.contains(lri.getNextHopIpList().get(0))) { Optional vpnInstanceOpDataEntryOptional = fibUtil.getVpnInstanceOpData(rd); @@ -1329,6 +1381,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vpnNameOpt = fibUtil.getVpnNameFromRd(vrfEntry.getParentVpnRd()); if (vpnNameOpt.isPresent()) { vpnId = fibUtil.getVpnId(vpnNameOpt.get()); @@ -1346,9 +1399,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase opVpnInterface = MDSALUtil - .read(dataBroker, LogicalDatastoreType.OPERATIONAL, - fibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName)); + Optional opVpnInterface = tx + .read(FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName)).get(); if (opVpnInterface.isPresent()) { long associatedVpnId = fibUtil.getVpnId(vpnName); if (vpnId != associatedVpnId) { @@ -1367,11 +1419,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase + configTx.delete(VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, vrfEntry.getDestPrefix()))); } } handleAdjacencyAndVpnOpInterfaceDeletion(vrfEntry, ifName, vpnName, tx); @@ -1390,40 +1441,37 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase tx) + throws ExecutionException, InterruptedException { InstanceIdentifier adjacencyIid = FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()); - Optional adjacencyOptional = tx.read(LogicalDatastoreType.OPERATIONAL, adjacencyIid).checkedGet(); + Optional adjacencyOptional = tx.read(adjacencyIid).get(); if (adjacencyOptional.isPresent()) { if (adjacencyOptional.get().getAdjacencyType() != Adjacency.AdjacencyType.PrimaryAdjacency) { - tx.delete(LogicalDatastoreType.OPERATIONAL, - FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix())); + tx.delete(FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix())); } else { - tx.merge(LogicalDatastoreType.OPERATIONAL, adjacencyIid, + tx.merge(adjacencyIid, new AdjacencyBuilder(adjacencyOptional.get()).setMarkedForDeletion(true).build()); } } - Optional optAdjacencies = - tx.read(LogicalDatastoreType.OPERATIONAL, - FibUtil.getAdjListPathOp(ifName, vpnName)).checkedGet(); + Optional optAdjacencies = tx.read(FibUtil.getAdjListPathOp(ifName, vpnName)).get(); if (!optAdjacencies.isPresent() || optAdjacencies.get().getAdjacency() == null) { return; } - if (optAdjacencies.get().getAdjacency().stream().count() <= 2 - && optAdjacencies.get().getAdjacency().stream().allMatch(adjacency -> + @NonNull List adjacencies = optAdjacencies.get().nonnullAdjacency(); + if (adjacencies.size() <= 2 + && adjacencies.stream().allMatch(adjacency -> adjacency.getAdjacencyType() == Adjacency.AdjacencyType.PrimaryAdjacency && adjacency.isMarkedForDeletion() != null && adjacency.isMarkedForDeletion() )) { LOG.info("Clean up vpn interface {} to vpn {} list.", ifName, vpnName); - tx.delete(LogicalDatastoreType.OPERATIONAL, - FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName)); + tx.delete(FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName)); } } @@ -1458,24 +1506,29 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { - for (final VpnToDpnList curDpn : vpnToDpnList) { - - baseVrfEntryHandler.makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), vrfEntry, - vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, tx, null); - if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) { - optionalLabel.ifPresent(label -> makeLFibTableEntry(curDpn.getDpnId(), label, null, + () -> Collections.singletonList( + txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { + for (final VpnToDpnList curDpn : vpnToDpnList) { + + baseVrfEntryHandler.makeConnectedRoute(curDpn.getDpnId(), vpnInstance.getVpnId(), + vrfEntry, vrfTableKey.getRouteDistinguisher(), null, NwConstants.DEL_FLOW, + TransactionAdapter.toWriteTransaction(tx), null); + if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.SELF_IMPORTED) { + optionalLabel.ifPresent(label -> makeLFibTableEntry(curDpn.getDpnId(), label, null, DEFAULT_FIB_FLOW_PRIORITY, NwConstants.DEL_FLOW, tx)); - } + } - installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnInstance.getVpnId(), + installSubnetBroadcastAddrDropRule(curDpn.getDpnId(), rd, vpnInstance.getVpnId(), vrfEntry, NwConstants.DEL_FLOW, tx); - } - }))); + } + }))); } optionalLabel.ifPresent(label -> { - synchronized (label.toString().intern()) { - LabelRouteInfo lri = getLabelRouteInfo(label); + final LabelRouteInfoKey lriKey = new LabelRouteInfoKey(label); + final ReentrantLock lock = lockFor(lriKey); + lock.lock(); + try { + LabelRouteInfo lri = getLabelRouteInfo(lriKey); if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopAddressList, lri)) { Optional vpnInstanceOpDataEntryOptional = fibUtil.getVpnInstanceOpData(rd); @@ -1497,6 +1550,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase extraRouteOptional; //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn if (usedRds != null && !usedRds.isEmpty()) { - jobKey = FibUtil.getJobKeyForRdPrefix(usedRds.get(0), vrfEntry.getDestPrefix()); if (usedRds.size() > 1) { LOG.error("The extra route prefix is still present in some DPNs"); return ; @@ -1522,27 +1576,35 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { + jobCoordinator.enqueueJob(FibUtil.getJobKeyForRdPrefix(rd, vrfEntry.getDestPrefix()), + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { if (localDpnIdList.size() <= 0) { for (VpnToDpnList curDpn : vpnToDpnList) { baseVrfEntryHandler.deleteRemoteRoute(BigInteger.ZERO, curDpn.getDpnId(), - vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx); + vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, + TransactionAdapter.toWriteTransaction(tx)); } } else { for (BigInteger localDpnId : localDpnIdList) { for (VpnToDpnList curDpn : vpnToDpnList) { - if (!curDpn.getDpnId().equals(localDpnId)) { + if (!Objects.equals(curDpn.getDpnId(), localDpnId)) { baseVrfEntryHandler.deleteRemoteRoute(localDpnId, curDpn.getDpnId(), - vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, tx); + vpnInstance.getVpnId(), vrfTableKey, vrfEntry, extraRouteOptional, + TransactionAdapter.toWriteTransaction(tx)); } } } } + if (extraRouteOptional.isPresent()) { + //Remove select groups only for extra-routes + nextHopManager.removeNextHopPointer(nextHopManager + .getRemoteSelectGroupKey(vpnInstance.getVpnId(), vrfEntry.getDestPrefix())); + nextHopManager.removeNextHopPointer(nextHopManager + .getLocalSelectGroupKey(vpnInstance.getVpnId(), vrfEntry.getDestPrefix())); + } })), MAX_RETRIES); } @@ -1571,10 +1633,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase instructions, int priority, - int addOrRemove, WriteTransaction tx) { + private void makeLFibTableEntry(BigInteger dpId, long label, @Nullable List instructions, + int priority, int addOrRemove, TypedWriteTransaction tx) { if (tx == null) { - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit( + ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, newTx -> makeLFibTableEntry(dpId, label, instructions, priority, addOrRemove, newTx)), LOG, "Error making LFIB table entry"); return; @@ -1599,9 +1661,9 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase { - for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + + final ReentrantLock lock = lockFor(vpnInstance); + lock.lock(); + try { + futures.add(retryingTxRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> { + for (final VrfEntry vrfEntry : vrfTable.get().nonnullVrfEntry()) { SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class); if (subnetRoute != null) { long elanTag = subnetRoute.getElantag(); @@ -1653,7 +1718,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry); LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get()); if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, lri)) { - if (lri.getDpnId().equals(dpnId)) { + if (Objects.equals(lri.getDpnId(), dpnId)) { try { int etherType = NWUtil.getEtherTypeFromIpPrefix( vrfEntry.getDestPrefix()); @@ -1674,7 +1739,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase txnObjects = new ArrayList<>(); bgpRouteVrfEntryHandler.createRemoteFibEntry(dpnId, vpnId, - vrfTable.get().getRouteDistinguisher(), vrfEntry, tx, txnObjects); + vrfTable.get().getRouteDistinguisher(), vrfEntry, + TransactionAdapter.toWriteTransaction(tx), txnObjects); } else { createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(), vrfEntry, tx); @@ -1686,6 +1752,8 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase> listenableFuture = Futures.allAsList(futures); Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor()); } + } finally { + lock.unlock(); } return futures; }); @@ -1701,12 +1769,16 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vrfTable = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id); if (vrfTable.isPresent()) { jobCoordinator.enqueueJob(FibUtil.getJobKeyForVpnIdDpnId(vpnId, dpnId), - () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { - synchronized (vpnInstance.getVpnInstanceName().intern()) { - vrfTable.get().getVrfEntry().stream() - .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin())) - .forEach(bgpRouteVrfEntryHandler.getConsumerForCreatingRemoteFib(dpnId, vpnId, - rd, remoteNextHopIp, vrfTable, tx, txnObjects)); + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { + final ReentrantLock lock = lockFor(vpnInstance); + lock.lock(); + try { + vrfTable.get().nonnullVrfEntry().stream() + .filter(vrfEntry -> RouteOrigin.BGP == RouteOrigin.value(vrfEntry.getOrigin())) + .forEach(bgpRouteVrfEntryHandler.getConsumerForCreatingRemoteFib(dpnId, vpnId, + rd, remoteNextHopIp, vrfTable, TransactionAdapter.toWriteTransaction(tx), txnObjects)); + } finally { + lock.unlock(); } }))); } @@ -1727,8 +1799,10 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { - synchronized (vpnInstance.getVpnInstanceName().intern()) { + () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { + final ReentrantLock lock = lockFor(vpnInstance); + lock.lock(); + try { VrfTablesKey vrfTablesKey = new VrfTablesKey(rd); VrfEntry vrfEntry = getVrfEntry(dataBroker, rd, destPrefix); if (vrfEntry == null) { @@ -1761,14 +1835,16 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase extraRouteOptional = Optional.absent(); - if (usedRds.size() != 0) { + if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.STATIC && usedRds.size() != 0) { extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, fibUtil.getVpnNameFromId(vpnInstance.getVpnId()), usedRds.get(0), vrfEntry.getDestPrefix()); } baseVrfEntryHandler.deleteRemoteRoute(null, localDpnId, vpnId, vrfTablesKey, modVrfEntry, - extraRouteOptional, tx); + extraRouteOptional, TransactionAdapter.toWriteTransaction(tx)); } + } finally { + lock.unlock(); } }))); } @@ -1785,18 +1861,26 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase> futures = new ArrayList<>(); if (vrfTable.isPresent()) { - synchronized (vpnInstance.getVpnInstanceName().intern()) { - futures.add(retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { + final ReentrantLock lock = lockFor(vpnInstance); + lock.lock(); + try { + futures.add(retryingTxRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { String vpnName = fibUtil.getVpnNameFromId(vpnInstance.getVpnId()); - for (final VrfEntry vrfEntry : vrfTable.get().getVrfEntry()) { + for (final VrfEntry vrfEntry : vrfTable.get().nonnullVrfEntry()) { + /* parentRd is only filled for external PNF cases where the interface on the external + * network VPN are used to cleanup the flows. For all other cases, use "rd" for + * #fibUtil.isInterfacePresentInDpn(). + * */ + String parentRd = vrfEntry.getParentVpnRd() != null ? vrfEntry.getParentVpnRd() + : rd; /* Handle subnet routes here */ SubnetRoute subnetRoute = vrfEntry.augmentation(SubnetRoute.class); if (subnetRoute != null && !fibUtil - .isInterfacePresentInDpn(vrfEntry.getParentVpnRd(), dpnId)) { + .isInterfacePresentInDpn(parentRd, dpnId)) { LOG.trace("SUBNETROUTE: cleanUpDpnForVpn: Cleaning subnetroute {} on dpn {}" + " for vpn {}", vrfEntry.getDestPrefix(), dpnId, rd); baseVrfEntryHandler.makeConnectedRoute(dpnId, vpnId, vrfEntry, rd, null, - NwConstants.DEL_FLOW, tx, null); + NwConstants.DEL_FLOW, TransactionAdapter.toWriteTransaction(tx), null); List routePaths = vrfEntry.getRoutePaths(); if (routePaths != null) { for (RoutePaths routePath : routePaths) { @@ -1831,7 +1915,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase nextHopList = FibHelper.getNextHopListFromRoutePaths(vrfEntry); LabelRouteInfo lri = getLabelRouteInfo(optionalLabel.get()); if (isPrefixAndNextHopPresentInLri(vrfEntry.getDestPrefix(), nextHopList, - lri) && lri.getDpnId().equals(dpnId)) { + lri) && Objects.equals(lri.getDpnId(), dpnId)) { deleteLocalFibEntry(vpnId, rd, vrfEntry); } } @@ -1858,16 +1942,20 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase> listenableFuture = Futures.allAsList(futures); @@ -1893,12 +1981,18 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase { - synchronized (vpnInstance.getVpnInstanceName().intern()) { - return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit( - tx -> vrfTable.get().getVrfEntry().stream() + final ReentrantLock lock = lockFor(vpnInstance); + lock.lock(); + try { + return Collections.singletonList( + txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, + tx -> vrfTable.get().nonnullVrfEntry().stream() .filter(vrfEntry -> RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) .forEach(bgpRouteVrfEntryHandler.getConsumerForDeletingRemoteFib(dpnId, vpnId, - remoteNextHopIp, vrfTable, tx, txnObjects)))); + remoteNextHopIp, vrfTable, TransactionAdapter.toWriteTransaction(tx), + txnObjects)))); + } finally { + lock.unlock(); } }); } @@ -1920,6 +2014,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase vrfEntryId = InstanceIdentifier.builder(FibEntries.class) .child(VrfTables.class, new VrfTablesKey(rd)) @@ -1969,7 +2064,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase { LOG.trace("Removing flow in FIB table for interVpnLink {}", interVpnLinkName); - ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> { + ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> { for (BigInteger dpId : targetDpns) { LOG.debug("Removing flow: VrfEntry=[prefix={} label={}] dpn {} for InterVpnLink {} in LFIB", vrfEntry.getDestPrefix(), label, dpId, interVpnLinkName); @@ -1980,9 +2075,9 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase nextHopAddressList, LabelRouteInfo lri) { - return lri != null && lri.getPrefix().equals(prefix) + return lri != null && Objects.equals(lri.getPrefix(), prefix) && nextHopAddressList.contains(lri.getNextHopIpList().get(0)); } @@ -2002,4 +2097,13 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase