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.netvirt.vpnmanager.VpnUtil.requireNonNullElse;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
-import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
+import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
import org.opendaylight.genius.mdsalutil.NwConstants;
import org.opendaylight.genius.mdsalutil.cache.InstanceIdDataObjectCache;
import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
import org.opendaylight.infrautils.caches.CacheProvider;
import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.label.route.map.LabelRouteInfoKey;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
private boolean canHandleNewVpnInterface(final InstanceIdentifier<VpnInterface> identifier,
final VpnInterface vpnInterface, String vpnName) {
- synchronized (vpnName.intern()) {
+ // FIXME: separate this out somehow?
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+ lock.lock();
+ try {
if (isVpnInstanceReady(vpnName)) {
return true;
}
addToUnprocessedVpnInterfaces(identifier, vpnInterface, vpnName);
return false;
+ } finally {
+ lock.unlock();
}
}
@SuppressWarnings("checkstyle:IllegalCatch")
private void addVpnInterface(final InstanceIdentifier<VpnInterface> identifier, final VpnInterface vpnInterface,
final @Nullable List<Adjacency> oldAdjs, final @Nullable List<Adjacency> newAdjs) {
- for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(vpnInterface.getVpnInstanceNames(),
- Collections.<VpnInstanceNames>emptyList())) {
+ for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames()) {
String vpnName = vpnInterfaceVpnInstance.getVpnName();
addVpnInterfaceCall(identifier, vpnInterface, oldAdjs, newAdjs, vpnName);
}
// TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
// (the inventory tx goes in last)
List<ListenableFuture<Void>> futures = new ArrayList<>();
+ //set of prefix used, as entry in prefix-to-interface datastore
+ // is prerequisite for refresh Fib to avoid race condition leading to
+ // missing remote next hop in bucket actions on bgp-vpn delete
+ Set<String> prefixListForRefreshFib = new HashSet<>();
ListenableFuture<Void> confFuture =
txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
confTx -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
+ " on dpn {}",
vpnInterface.getName(), vpnName, vpnInterface.getDpnId());
processVpnInterfaceUp(dpnId, vpnInterface, primaryRd, ifIndex, false,
- confTx, operTx, invTx, interfaceState, vpnName);
+ confTx, operTx, invTx, interfaceState, vpnName,
+ prefixListForRefreshFib);
if (oldAdjs != null && !oldAdjs.equals(newAdjs)) {
LOG.info("addVpnInterface: Adjacency changed upon VPNInterface {}"
+ " Update for swapping VPN {} case.", interfaceName, vpnName);
if (!isBgpVpnInternetVpn
|| vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
addNewAdjToVpnInterface(vpnInterfaceOpIdentifier,
- primaryRd, adj, dpnId, operTx, confTx, invTx);
+ primaryRd, adj, dpnId, operTx, confTx, invTx,
+ prefixListForRefreshFib);
}
}
}
}
}
})))));
+ Futures.addCallback(confFuture,
+ new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+ MoreExecutors.directExecutor());
futures.add(confFuture);
Futures.addCallback(confFuture, new PostVpnInterfaceWorker(interfaceName, true, "Config"),
MoreExecutors.directExecutor());
TypedWriteTransaction<Configuration> writeConfigTxn,
TypedWriteTransaction<Operational> writeOperTxn,
TypedReadWriteTransaction<Configuration> writeInvTxn,
- Interface interfaceState,
- final String vpnName) throws ExecutionException, InterruptedException {
+ Interface interfaceState, final String vpnName,
+ Set<String> prefixListForRefreshFib) throws ExecutionException, InterruptedException {
final String interfaceName = vpnInterface.getName();
Optional<VpnInterfaceOpDataEntry> optOpVpnInterface = vpnUtil.getVpnInterfaceOpDataEntry(interfaceName,
vpnName);
null/*ipAddressSourceValuePair*/,
true /* add */);
processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
- vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
+ vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
if (!isBgpVpnInternetVpn) {
vpnUtil.bindService(vpnName, interfaceName, false /*isTunnelInterface*/);
}
null/*ipAddressSourceValuePair*/,
true /* add */);
processVpnInterfaceAdjacencies(dpId, lportTag, vpnName, primaryRd, interfaceName,
- vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
+ vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState, prefixListForRefreshFib);
if (!isBgpVpnInternetVpn) {
vpnUtil.bindService(vpnName, interfaceName, false/*isTunnelInterface*/);
}
LOG.trace("No config adjacencies present for vpninterface {}", vpnInterface);
return;
}
- List<Adjacency> adjacencies = requireNonNullElse(optAdjacencies.get().getAdjacency(), emptyList());
+ List<Adjacency> adjacencies = optAdjacencies.get().nonnullAdjacency();
for (Adjacency adjacency : adjacencies) {
if (adjacency.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
continue;
continue;
}
addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adjacency,
- dpId, writeOperTxn, writeConfigTxn, writeInvTxn);
+ dpId, writeOperTxn, writeConfigTxn, writeInvTxn, prefixListForRefreshFib);
}
} catch (ReadFailedException e) {
LOG.error("processVpnInterfaceUp: Failed to read data store for interface {} vpn {} rd {} dpn {}",
LOG.info("VPN WITHDRAW: withdrawAdjacenciesForVpnFromBgp: Removed Fib Entry rd {}"
+ " prefix {} for interface {} in vpn {}", rd, nextHop.getIpAddress(),
interfaceName, vpnName);
- } else {
+ } else if (nextHop.getNextHopIpList() != null) {
// Perform similar operation as interface delete event for extraroutes.
String allocatedRd = nextHop.getVrfId();
- for (String nh : requireNonNullElse(nextHop.getNextHopIpList(),
- Collections.<String>emptyList())) {
+ for (String nh : nextHop.getNextHopIpList()) {
deleteExtraRouteFromCurrentAndImportingVpns(
vpnName, nextHop.getIpAddress(), nh, allocatedRd, interfaceName, writeConfigTxn,
writeOperTx);
TypedWriteTransaction<Configuration> writeConfigTxn,
TypedWriteTransaction<Operational> writeOperTxn,
TypedReadWriteTransaction<Configuration> writeInvTxn,
- Interface interfaceState)
+ Interface interfaceState, Set<String> prefixListForRefreshFib)
throws ExecutionException, InterruptedException {
InstanceIdentifier<VpnInterface> identifier = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
// Read NextHops
boolean isL3VpnOverVxLan = VpnUtil.isL3VpnOverVxLan(l3vni);
VrfEntry.EncapType encapType = isL3VpnOverVxLan ? VrfEntry.EncapType.Vxlan : VrfEntry.EncapType.Mplsgre;
VpnPopulator registeredPopulator = L3vpnRegistry.getRegisteredPopulator(encapType);
- List<Adjacency> nextHops = (adjacencies != null) ? adjacencies.getAdjacency() : emptyList();
+ List<Adjacency> nextHops = adjacencies != null ? adjacencies.getAdjacency() : emptyList();
List<Adjacency> value = new ArrayList<>();
for (Adjacency nextHop : nextHops) {
String rd = primaryRd;
LOG.debug("processVpnInterfaceAdjacencies: Adding prefix {} to interface {} with nextHops {} on dpn {}"
+ " for vpn {}", prefix, interfaceName, nhList, dpnId, vpnName);
- Prefixes prefixes = (intfnetworkUuid != null)
+ Prefixes prefixes = intfnetworkUuid != null
? VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, intfnetworkUuid ,networkType,
segmentationId, prefixCue) :
VpnUtil.getPrefixToInterface(dpnId, interfaceName, prefix, prefixCue);
//Extra route adjacency
String prefix = VpnUtil.getIpPrefix(nextHop.getIpAddress());
String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
- synchronized (vpnPrefixKey.intern()) {
+ // FIXME: separate this out somehow?
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
+ lock.lock();
+ try {
java.util.Optional<String> rdToAllocate = vpnUtil
.allocateRdForExtraRouteAndUpdateUsedRdsMap(vpnId, null, prefix, vpnName,
nextHop.getNextHopIpList().get(0), dpnId);
LOG.error("processVpnInterfaceAdjacencies: No rds to allocate extraroute {}", prefix);
continue;
}
+ } finally {
+ lock.unlock();
}
LOG.info("processVpnInterfaceAdjacencies: Added prefix {} and nextHopList {} as extra-route for vpn{}"
+ " interface {} on dpn {}", nextHop.getIpAddress(), nextHop.getNextHopIpList(), vpnName,
// Please note that primary adjacency will use a subnet-gateway-mac-address that
// can be different from the gateway-mac-address within the VRFEntry as the
// gateway-mac-address is a superset.
- RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
- : RouteOrigin.STATIC;
+ RouteOrigin origin = VpnUtil.getRouteOrigin(nextHop.getAdjacencyType());
L3vpnInput input = new L3vpnInput().setNextHop(nextHop).setRd(rd).setVpnName(vpnName)
.setInterfaceName(interfaceName).setNextHopIp(nextHopIp).setPrimaryRd(primaryRd)
.setSubnetGatewayMacAddress(vpnInterfaceSubnetGwMacAddress).setRouteOrigin(origin);
}
if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
vpnManager.addExtraRoute(vpnName, nextHop.getIpAddress(), nextHop.getNextHopIpList().get(0), rd,
- vpnName, l3vni, origin,
- interfaceName, operationalAdjacency, encapType, writeConfigTxn);
+ vpnName, l3vni, origin, interfaceName, operationalAdjacency, encapType, prefixListForRefreshFib,
+ writeConfigTxn);
}
value.add(operationalAdjacency);
}
for (Adjacency nextHop : aug.getAdjacency()) {
// Adjacencies other than primary Adjacencies are handled in the addExtraRoute call above.
if (nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
- RouteOrigin origin = nextHop.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
- : RouteOrigin.STATIC;
+ RouteOrigin origin = VpnUtil.getRouteOrigin(nextHop.getAdjacencyType());
input.setNextHop(nextHop).setRd(nextHop.getVrfId()).setRouteOrigin(origin);
registeredPopulator.populateFib(input, writeConfigTxn);
}
}
String prefix = vrfEntry.getDestPrefix();
String gwMac = vrfEntry.getGatewayMacAddress();
- requireNonNullElse(vrfEntry.getRoutePaths(),
- Collections.<RoutePaths>emptyList()).forEach(routePath -> {
- String nh = routePath.getNexthopAddress();
- int label = routePath.getLabel().intValue();
- if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
- vrfEntry.getOrigin()))) {
- LOG.info(
- "handleVpnsExportingRoutesImporting: Importing fib entry rd {}"
- + " prefix {} nexthop {} label {} to vpn {} vpnRd {}",
- vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
- fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
- Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
- 0 /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
- confTx);
- } else {
- LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
- + " rd {} prefix {} nexthop {} label {} to vpn {} vpnRd {}",
- vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
- SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
- importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
- confTx);
- }
- });
+ vrfEntry.nonnullRoutePaths().forEach(routePath -> {
+ String nh = routePath.getNexthopAddress();
+ int label = routePath.getLabel().intValue();
+ if (FibHelper.isControllerManagedVpnInterfaceRoute(RouteOrigin.value(
+ vrfEntry.getOrigin()))) {
+ LOG.info(
+ "handleVpnsExportingRoutesImporting: Importing fib entry rd {}"
+ + " prefix {} nexthop {} label {} to vpn {} vpnRd {}",
+ vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
+ fibManager.addOrUpdateFibEntry(vpnRd, null /*macAddress*/, prefix,
+ Collections.singletonList(nh), VrfEntry.EncapType.Mplsgre, label,
+ 0 /*l3vni*/, gwMac, vpn.getVrfId(), RouteOrigin.SELF_IMPORTED,
+ confTx);
+ } else {
+ LOG.info("handleVpnsExportingRoutes: Importing subnet route fib entry"
+ + " rd {} prefix {} nexthop {} label {} to vpn {} vpnRd {}",
+ vpn.getVrfId(), prefix, nh, label, vpnName, vpnRd);
+ SubnetRoute route = vrfEntry.augmentation(SubnetRoute.class);
+ importSubnetRouteForNewVpn(vpnRd, prefix, nh, label, route, vpn.getVrfId(),
+ confTx);
+ }
+ });
} catch (RuntimeException e) {
LOG.error("getNextHopAddressList: Exception occurred while importing route with rd {}"
+ " prefix {} routePaths {} to vpn {} vpnRd {}", vpn.getVrfId(),
LOG.trace("Received VpnInterface remove event: vpnInterface={}", vpnInterface);
final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
final String interfaceName = key.getName();
- for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(vpnInterface.getVpnInstanceNames(),
- Collections.<VpnInstanceNames>emptyList())) {
+ for (VpnInstanceNames vpnInterfaceVpnInstance : vpnInterface.nonnullVpnInstanceNames()) {
String vpnName = vpnInterfaceVpnInstance.getVpnName();
removeVpnInterfaceCall(identifier, vpnInterface, vpnName, interfaceName);
}
interfaceName, vpnInterface.getDpnId(), vpnName);
})))));
futures.add(configFuture);
- Futures.addCallback(configFuture, new PostVpnInterfaceWorker(interfaceName, false, "Config"));
+ Futures.addCallback(configFuture, new PostVpnInterfaceWorker(
+ interfaceName, false, "Config"), MoreExecutors.directExecutor());
return futures;
}, DJC_MAX_RETRIES);
}
InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
LogicalDatastoreType.OPERATIONAL, path);
+ boolean isNonPrimaryAdjIp = Boolean.FALSE;
String primaryRd = vpnUtil.getVpnRd(vpnName);
LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
interfaceName, dpnId, vpnName, primaryRd);
List<String> nhList;
if (nextHop.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
nhList = getNextHopForNonPrimaryAdjacency(nextHop, vpnName, dpnId, interfaceName);
+ isNonPrimaryAdjIp = Boolean.TRUE;
} else {
// This is a primary adjacency
nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
interfaceName, writeInvTxn);
}
if (!nhList.isEmpty()) {
- if (Objects.equals(rd, vpnName)) {
+ if (Objects.equals(primaryRd, vpnName)) {
//this is an internal vpn - the rd is assigned to the vpn instance name;
//remove from FIB directly
nhList.forEach(removeAdjacencyFromInternalVpn(nextHop, vpnName,
}
String ip = nextHop.getIpAddress().split("/")[0];
LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, ip);
- if (vpnVipToPort != null) {
+ if (vpnVipToPort != null && vpnVipToPort.getPortName().equals(interfaceName)) {
vpnUtil.removeLearntVpnVipToPort(vpnName, ip, null);
LOG.info("removeAdjacenciesFromVpn: VpnInterfaceManager removed LearntVpnVipToPort entry"
+ " for Interface {} ip {} on dpn {} for vpn {}",
vpnVipToPort.getPortName(), ip, dpnId, vpnName);
}
+ // Remove the MIP-IP from VpnPortIpToPort.
+ if (isNonPrimaryAdjIp) {
+ VpnPortipToPort persistedIp = vpnUtil.getVpnPortipToPort(vpnName, ip);
+ if (persistedIp != null && persistedIp.isLearntIp()
+ && persistedIp.getPortName().equals(interfaceName)) {
+ VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
+ LOG.info(
+ "removeAdjacenciesFromVpn: Learnt-IP: {} interface {} of vpn {} removed "
+ + "from VpnPortipToPort",
+ persistedIp.getPortFixedip(), persistedIp.getPortName(), vpnName);
+ }
+ }
VpnPortipToPort vpnPortipToPort = vpnUtil.getNeutronPortFromVpnPortFixedIp(vpnName, ip);
if (vpnPortipToPort != null) {
VpnUtil.removeVpnPortFixedIpToPort(dataBroker, vpnName, ip, null);
String vpnNamePrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
LOG.info("remove adjacencies for nexthop {} vpnName {} interfaceName {} dpnId {}",
nextHop, vpnName, interfaceName, dpnId);
- synchronized (vpnNamePrefixKey.intern()) {
+ // FIXME: separate this out somehow?
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnNamePrefixKey);
+ lock.lock();
+ try {
if (vpnUtil.removeOrUpdateDSForExtraRoute(vpnName, primaryRd, dpnId.toString(), interfaceName,
prefix, nextHop.getNextHopIpList().get(0), nh, writeOperTx)) {
//If extra-route is present behind at least one VM, then do not remove or update
}
fibManager.removeOrUpdateFibEntry(vpnName, nextHop.getIpAddress(), nh,
writeConfigTxn);
+ } finally {
+ lock.unlock();
}
LOG.info("removeAdjacenciesFromVpn: removed/updated FIB with rd {} prefix {}"
+ " nexthop {} for interface {} on dpn {} for internal vpn {}",
LOG.trace("Received VpnInterface update event: original={}, update={}", original, update);
LOG.info("update: VPN Interface update event - intfName {} on dpn {} oldVpn {} newVpn {}", update.getName(),
update.getDpnId(), original.getVpnInstanceNames(), update.getVpnInstanceNames());
+ if (original.equals(update)) {
+ LOG.info("update: original {} update {} are same. No update required.", original, update);
+ return;
+ }
final String vpnInterfaceName = update.getName();
final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
LOG.info("VPN Interface update event - intfName {}", vpnInterfaceName);
private boolean handleVpnInstanceUpdateForVpnInterface(InstanceIdentifier<VpnInterface> identifier,
VpnInterface original, VpnInterface update,
List<ListenableFuture<Void>> futures) {
- boolean isVpnInstanceUpdate = Boolean.FALSE;
+ boolean isVpnInstanceUpdate = false;
final VpnInterfaceKey key = identifier.firstKeyOf(VpnInterface.class);
final String interfaceName = key.getName();
- List<String> oldVpnList = vpnUtil.getVpnListForVpnInterface(original);
+ List<String> oldVpnList = VpnUtil.getVpnListForVpnInterface(original);
List<String> oldVpnListCopy = new ArrayList<>();
oldVpnListCopy.addAll(oldVpnList);
- List<String> newVpnList = vpnUtil.getVpnListForVpnInterface(update);
+ List<String> newVpnList = VpnUtil.getVpnListForVpnInterface(update);
List<String> newVpnListCopy = new ArrayList<>();
newVpnListCopy.addAll(newVpnList);
*
*
*/
- isVpnInstanceUpdate = Boolean.TRUE;
+ isVpnInstanceUpdate = true;
if (VpnUtil.isDualRouterVpnUpdate(oldVpnListCopy, newVpnListCopy)) {
if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
- && (oldVpnList.size() == 1 && newVpnList.size() == 0)) {
+ && oldVpnList.size() == 1 && newVpnList.isEmpty()) {
//Identify the external BGP-VPN Instance and pass that value as newVpnList
List<String> externalBgpVpnList = new ArrayList<>();
for (String newVpnName : newVpnListCopy) {
externalBgpVpnList, oldVpnListCopy, futures);
} else if ((oldVpnListCopy.size() == 2 || oldVpnListCopy.size() == 3)
- && (oldVpnList.size() == 0 && newVpnList.size() == 1)) {
+ && oldVpnList.isEmpty() && newVpnList.size() == 1) {
//Identify the router VPN Instance and pass that value as oldVpnList
List<String> routerVpnList = new ArrayList<>();
for (String newVpnName : newVpnListCopy) {
List<String> newVpnList, List<String> oldVpnListCopy,
List<ListenableFuture<Void>> futures) {
final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
- final List<Adjacency> oldAdjs = (origAdjs != null && origAdjs.getAdjacency() != null)
+ final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency() != null
? origAdjs.getAdjacency() : new ArrayList<>();
final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
- final List<Adjacency> newAdjs = (updateAdjs != null && updateAdjs.getAdjacency() != null)
+ final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency() != null
? updateAdjs.getAdjacency() : new ArrayList<>();
boolean isOldVpnRemoveCallExecuted = false;
!= null ? updateAdjs.getAdjacency() : new ArrayList<>();
final BigInteger dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
- for (VpnInstanceNames vpnInterfaceVpnInstance : requireNonNullElse(update.getVpnInstanceNames(),
- Collections.<VpnInstanceNames>emptyList())) {
+ for (VpnInstanceNames vpnInterfaceVpnInstance : update.nonnullVpnInstanceNames()) {
String newVpnName = vpnInterfaceVpnInstance.getVpnName();
List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
// TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
- futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
- futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL, operTx -> {
- InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
+ //set of prefix used as entry in prefix-to-interface datastore
+ // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
+ // in bucket actions on bgp-vpn delete
+ Set<String> prefixListForRefreshFib = new HashSet<>();
+ ListenableFuture<Void> configTxFuture = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+ confTx -> futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL,
+ operTx -> {
+ InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
- LOG.info("VPN Interface update event - intfName {} onto vpnName {} running config-driven",
- update.getName(), newVpnName);
- //handle both addition and removal of adjacencies
- //currently, new adjacency may be an extra route
- boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
- if (!oldAdjs.equals(newAdjs)) {
- for (Adjacency adj : copyNewAdjs) {
- if (copyOldAdjs.contains(adj)) {
- copyOldAdjs.remove(adj);
- } else {
- // add new adjacency
- if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
- addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
- dpnId, operTx, confTx, confTx);
+ LOG.info("VPN Interface update event-intfName {} onto vpnName {} running config-driven",
+ update.getName(), newVpnName);
+ //handle both addition and removal of adjacencies
+ // currently, new adjacency may be an extra route
+ boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
+ if (!oldAdjs.equals(newAdjs)) {
+ for (Adjacency adj : copyNewAdjs) {
+ if (copyOldAdjs.contains(adj)) {
+ copyOldAdjs.remove(adj);
+ } else {
+ // add new adjacency
+ if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
+ addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
+ dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
+ }
+ LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
+ + " added to vpn interface {} on vpn {} dpnId {}",
+ adj.getIpAddress(), adj.getNextHopIpList(), adj.getLabel(),
+ adj.getSubnetId(), update.getName(), newVpnName, dpnId);
}
- LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} added to"
- + " vpn interface {} on vpn {} dpnId {}",
- adj.getIpAddress(), adj.getNextHopIpList(),
- adj.getLabel(), adj.getSubnetId(), update.getName(),
- newVpnName, dpnId);
}
- }
- for (Adjacency adj : copyOldAdjs) {
- if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
- if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
+ for (Adjacency adj : copyOldAdjs) {
+ if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
+ if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
&& !adj.isPhysNetworkFunc()) {
- delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
- operTx, confTx);
- //remove FIB entry
- String vpnRd = vpnUtil.getVpnRd(newVpnName);
- LOG.debug("update: remove prefix {} from the FIB and BGP entry "
+ delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId, operTx,
+ confTx);
+ //remove FIB entry
+ String vpnRd = vpnUtil.getVpnRd(newVpnName);
+ LOG.debug("update: remove prefix {} from the FIB and BGP entry "
+ "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
- //remove BGP entry
- fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
- if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
- bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
- }
- } else {
- delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
+ //remove BGP entry
+ fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), confTx);
+ if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
+ bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
+ }
+ } else {
+ delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
operTx, confTx);
+ }
}
- }
- LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
- + " vpn interface {} on vpn {}", adj.getIpAddress(), adj
- .getNextHopIpList(),
+ LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
+ + " vpn interface {} on vpn {}", adj.getIpAddress(), adj.getNextHopIpList(),
adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
+ }
}
- }
- }));
- }));
+ })));
+ Futures.addCallback(configTxFuture, new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+ MoreExecutors.directExecutor());
+ futures.add(configTxFuture);
for (ListenableFuture<Void> future : futures) {
ListenableFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
update.getName(), update.getVpnInstanceNames());
}
private void updateLabelMapper(Long label, List<String> nextHopIpList) {
+ final String labelStr = Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!")
+ .toString();
+ // FIXME: separate this out somehow?
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(labelStr);
+ lock.lock();
try {
- Preconditions.checkNotNull(label, "updateLabelMapper: label cannot be null or empty!");
- synchronized (label.toString().intern()) {
- InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
- .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
- Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
- LogicalDatastoreType.OPERATIONAL, lriIid);
- if (opResult.isPresent()) {
- LabelRouteInfo labelRouteInfo =
- new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
- SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
- labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
- }
+ InstanceIdentifier<LabelRouteInfo> lriIid = InstanceIdentifier.builder(LabelRouteMap.class)
+ .child(LabelRouteInfo.class, new LabelRouteInfoKey(label)).build();
+ Optional<LabelRouteInfo> opResult = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+ LogicalDatastoreType.OPERATIONAL, lriIid);
+ if (opResult.isPresent()) {
+ LabelRouteInfo labelRouteInfo =
+ new LabelRouteInfoBuilder(opResult.get()).setNextHopIpList(nextHopIpList).build();
+ SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, lriIid,
+ labelRouteInfo, VpnUtil.SINGLE_TRANSACTION_BROKER_NO_RETRY);
}
LOG.info("updateLabelMapper: Updated label rotue info for label {} with nextHopList {}", label,
nextHopIpList);
} catch (TransactionCommitFailedException e) {
LOG.error("updateLabelMapper: Failed to commit to data store for label {} nexthopList {}", label,
nextHopIpList);
+ } finally {
+ lock.unlock();
}
}
Adjacency adj, BigInteger dpnId,
TypedWriteTransaction<Operational> writeOperTxn,
TypedWriteTransaction<Configuration> writeConfigTxn,
- TypedReadWriteTransaction<Configuration> writeInvTxn)
+ TypedReadWriteTransaction<Configuration> writeInvTxn,
+ Set<String> prefixListForRefreshFib)
throws ExecutionException, InterruptedException {
String interfaceName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getName();
String configVpnName = identifier.firstKeyOf(VpnInterfaceOpDataEntry.class).getVpnInstanceName();
currVpnIntf.getName());
if (interfaceState != null) {
processVpnInterfaceAdjacencies(dpnId, currVpnIntf.getLportTag().intValue(), vpnName, primaryRd,
- currVpnIntf.getName(),
- vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState);
+ currVpnIntf.getName(), vpnId, writeConfigTxn, writeOperTxn, writeInvTxn, interfaceState,
+ prefixListForRefreshFib);
}
}
if (adj.getNextHopIpList() != null && !adj.getNextHopIpList().isEmpty()
&& adj.getAdjacencyType() != AdjacencyType.PrimaryAdjacency) {
- RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency ? RouteOrigin.LOCAL
+ RouteOrigin origin = adj.getAdjacencyType() == AdjacencyType.LearntIp ? RouteOrigin.DYNAMIC
: RouteOrigin.STATIC;
String nh = adj.getNextHopIpList().get(0);
String vpnPrefixKey = VpnUtil.getVpnNamePrefixKey(vpnName, prefix);
- synchronized (vpnPrefixKey.intern()) {
+ // FIXME: separate out to somehow?
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnPrefixKey);
+ lock.lock();
+ try {
java.util.Optional<String> rdToAllocate = vpnUtil.allocateRdForExtraRouteAndUpdateUsedRdsMap(
vpnId, null, prefix, vpnName, nh, dpnId);
if (rdToAllocate.isPresent()) {
int label = operationalAdjacency.getLabel().intValue();
vpnManager.addExtraRoute(vpnName, adj.getIpAddress(), nh, rdToAllocate.get(),
currVpnIntf.getVpnInstanceName(), l3vni, origin,
- currVpnIntf.getName(), operationalAdjacency, encapType, writeConfigTxn);
+ currVpnIntf.getName(), operationalAdjacency, encapType,
+ prefixListForRefreshFib, writeConfigTxn);
LOG.info("addNewAdjToVpnInterface: Added extra route ip {} nh {} rd {} vpnname {} label {}"
+ " Interface {} on dpn {}", adj.getIpAddress(), nh, rdToAllocate.get(),
vpnName, label, currVpnIntf.getName(), dpnId);
vpnUtil.getVpnName(vpn.getVpnId()), nh, dpnId)
.ifPresent(
rds -> vpnManager.addExtraRoute(
- vpnUtil.getVpnName(vpn.getVpnId()),
- adj.getIpAddress(), nh, rds,
- currVpnIntf.getVpnInstanceName(), l3vni,
- RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(),
- opAdjacency, encapType, writeConfigTxn));
+ vpnUtil.getVpnName(vpn.getVpnId()), adj.getIpAddress(),
+ nh, rds, currVpnIntf.getVpnInstanceName(), l3vni,
+ RouteOrigin.SELF_IMPORTED, currVpnIntf.getName(), opAdjacency,
+ encapType, prefixListForRefreshFib, writeConfigTxn));
}
});
}
+ } finally {
+ lock.unlock();
}
} else if (adj.isPhysNetworkFunc()) { // PNF adjacency.
LOG.trace("addNewAdjToVpnInterface: Adding prefix {} to interface {} for vpn {}", prefix,
for (Adjacency adjacency : adjacencies) {
if (Objects.equals(adjacency.getIpAddress(), adj.getIpAddress())) {
String rd = adjacency.getVrfId();
+ InstanceIdentifier<Adjacency> adjIdentifier = VpnUtil
+ .getVpnInterfaceOpDataEntryAdjacencyIdentifier(currVpnIntf.getName(),
+ currVpnIntf.getVpnInstanceName(), adj.getIpAddress());
+ LOG.debug("delAdjFromVpnInterface: adjIdentifier {}", adjIdentifier);
+ writeOperTxn.delete(adjIdentifier);
if (adj.getNextHopIpList() != null) {
for (String nh : adj.getNextHopIpList()) {
deleteExtraRouteFromCurrentAndImportingVpns(
LOG.info("createFibEntryForRouterInterface: Router interface {} for vpn {} rd {} prefix {} label {}"
+ " macAddress {} processed successfully;", interfaceName, vpnName, primaryRd, prefix, label,
macAddress);
- return;
+ } else {
+ LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
+ + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}",
+ interfaceName, primaryRd, vpnName);
}
}
- LOG.error("createFibEntryForRouterInterface: VPN Interface {} of router addition failed as primary"
- + " adjacency for this vpn interface could not be obtained. rd {} vpnName {}", interfaceName,
- primaryRd, vpnName);
}
protected void deleteFibEntryForRouterInterface(VpnInterface vpnInterface,
Adjacencies adjs = vpnInterface.augmentation(Adjacencies.class);
String rd = vpnUtil.getVpnRd(vpnName);
if (adjs != null) {
- List<Adjacency> adjsList = requireNonNullElse(adjs.getAdjacency(), emptyList());
+ List<Adjacency> adjsList = adjs.nonnullAdjacency();
for (Adjacency adj : adjsList) {
if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency) {
String primaryInterfaceIp = adj.getIpAddress();
fibManager.removeFibEntry(rd, prefix, writeConfigTxn);
LOG.info("deleteFibEntryForRouterInterface: FIB for router interface {} deleted for vpn {} rd {}"
+ " prefix {}", vpnInterface.getName(), vpnName, rd, prefix);
- return;
}
}
} else {
}
public void processSavedInterfaces(String vpnInstanceName, boolean hasVpnInstanceCreatedSuccessfully) {
- synchronized (vpnInstanceName.intern()) {
+ // FIXME: separate out to somehow?
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnInstanceName);
+ lock.lock();
+ try {
ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
unprocessedVpnInterfaces.get(vpnInstanceName);
if (vpnInterfaces != null) {
} else {
LOG.info("processSavedInterfaces: No interfaces in queue for VPN {}", vpnInstanceName);
}
+ } finally {
+ lock.unlock();
}
}
private void removeInterfaceFromUnprocessedList(InstanceIdentifier<VpnInterface> identifier,
VpnInterface vpnInterface) {
- synchronized (VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface).intern()) {
+ // FIXME: use VpnInstanceNamesKey perhaps? What about nulls?
+ final String firstVpnName = VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface);
+ final ReentrantLock lock = JvmGlobalLocks.getLockForString(firstVpnName);
+ lock.lock();
+ try {
ConcurrentLinkedQueue<UnprocessedVpnInterfaceData> vpnInterfaces =
- unprocessedVpnInterfaces.get(VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
+ unprocessedVpnInterfaces.get(firstVpnName);
if (vpnInterfaces != null) {
if (vpnInterfaces.remove(new UnprocessedVpnInterfaceData(identifier, vpnInterface))) {
LOG.info("removeInterfaceFromUnprocessedList: Removed vpn interface {} in vpn instance {} from "
- + "unprocessed list", vpnInterface.getName(),
- VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
+ + "unprocessed list", vpnInterface.getName(), firstVpnName);
}
} else {
- LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}",
- VpnHelper.getFirstVpnNameFromVpnInterface(vpnInterface));
+ LOG.info("removeInterfaceFromUnprocessedList: No interfaces in queue for VPN {}", firstVpnName);
}
+ } finally {
+ lock.unlock();
}
}
LOG.debug("There is no adjacency available for vpnInterface:{}", vpnInterface);
return;
}
- List<Adjacency> operationVpnAdjacencies = requireNonNullElse(vpnInterfaceOptional.get()
- .augmentation(AdjacenciesOp.class).getAdjacency(), emptyList());
+ List<Adjacency> operationVpnAdjacencies = vpnInterfaceOptional.get()
+ .augmentation(AdjacenciesOp.class).nonnullAdjacency();
// Due to insufficient rds, some of the extra route wont get processed when it is added.
// The unprocessed adjacencies will be present in config vpn interface DS but will be missing
// in operational DS. These unprocessed adjacencies will be handled below.
if (vpnUtil.isAdjacencyEligibleToVpn(adjacency, vpnName)) {
List<ListenableFuture<Void>> futures = new ArrayList<>();
futures.add(
- txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx ->
- futures.add(
+ txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx -> {
+ //set of prefix used, as entry in prefix-to-interface datastore
+ // is prerequisite for refresh Fib to avoid race condition leading
+ // to missing remote next hop in bucket actions on bgp-vpn delete
+ Set<String> prefixListForRefreshFib = new HashSet<>();
+ ListenableFuture<Void> configTxFuture =
txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
confTx -> addNewAdjToVpnInterface(existingVpnInterfaceId,
- primaryRd, adjacency, vpnInterfaceOptional.get()
- .getDpnId(), operTx, confTx, confTx)))));
+ primaryRd, adjacency, vpnInterfaceOptional.get().getDpnId(),
+ operTx, confTx, confTx, prefixListForRefreshFib));
+ Futures.addCallback(configTxFuture,
+ new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+ MoreExecutors.directExecutor());
+ futures.add(configTxFuture);
+ }));
return futures;
} else {
return emptyList();
}
}
}
+
+ private class VpnInterfaceCallBackHandler implements FutureCallback<Void> {
+ private final String primaryRd;
+ private final Set<String> prefixListForRefreshFib;
+
+ VpnInterfaceCallBackHandler(String primaryRd, Set<String> prefixListForRefreshFib) {
+ this.primaryRd = primaryRd;
+ this.prefixListForRefreshFib = prefixListForRefreshFib;
+ }
+
+ @Override
+ public void onSuccess(Void voidObj) {
+ prefixListForRefreshFib.forEach(prefix -> {
+ fibManager.refreshVrfEntry(primaryRd, prefix);
+ });
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ LOG.debug("write Tx config operation failed", throwable);
+ }
+ }
}