*/
package org.opendaylight.netvirt.neutronvpn;
-import java.math.BigInteger;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
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.TimeUnit;
import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
+import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
import org.opendaylight.mdsal.binding.api.DataBroker;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpns.rev150903.BgpvpnTypeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpns.rev150903.bgpvpns.attributes.bgpvpns.Bgpvpn;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
import org.slf4j.Logger;
@Singleton
public class NeutronBgpvpnChangeListener extends AbstractAsyncDataTreeChangeListener<Bgpvpn> {
+
private static final Logger LOG = LoggerFactory.getLogger(NeutronBgpvpnChangeListener.class);
- private final DataBroker dataBroker;
+
private final NeutronvpnManager nvpnManager;
private final IdManagerService idManager;
private final NeutronvpnUtils neutronvpnUtils;
+ private final NeutronBgpvpnUtils neutronBgpvpnUtils;
private final String adminRDValue;
@Inject
public NeutronBgpvpnChangeListener(final DataBroker dataBroker, final NeutronvpnManager neutronvpnManager,
- final IdManagerService idManager, final NeutronvpnUtils neutronvpnUtils) {
- super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
- .child(Bgpvpns.class).child(Bgpvpn.class), Executors.newSingleThreadExecutor(
- "NeutronBgpvpnChangeListener", LOG));
- this.dataBroker = dataBroker;
- nvpnManager = neutronvpnManager;
+ final IdManagerService idManager, final NeutronvpnUtils neutronvpnUtils,
+ final NeutronBgpvpnUtils neutronBgpvpnUtils) {
+ super(dataBroker, LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Neutron.class).child(Bgpvpns.class).child(Bgpvpn.class),
+ Executors.newSingleThreadExecutor("NeutronBgpvpnChangeListener", LOG));
+ this.nvpnManager = neutronvpnManager;
this.idManager = idManager;
this.neutronvpnUtils = neutronvpnUtils;
+ this.neutronBgpvpnUtils = neutronBgpvpnUtils;
BundleContext bundleContext = FrameworkUtil.getBundle(NeutronBgpvpnChangeListener.class).getBundleContext();
adminRDValue = bundleContext.getProperty(NeutronConstants.RD_PROPERTY_KEY);
init();
public void init() {
LOG.info("{} init", getClass().getSimpleName());
- createIdPool();
}
@Override
@SuppressWarnings("checkstyle:IllegalCatch")
public void add(InstanceIdentifier<Bgpvpn> identifier, Bgpvpn input) {
LOG.trace("Adding Bgpvpn : key: {}, value={}", identifier, input);
+
String vpnName = input.getUuid().getValue();
- if (isBgpvpnTypeL3(input.getType())) {
+ if (!isBgpvpnTypeL3(input.getType())) {
+ LOG.warn("BGPVPN type for VPN {} is not L3", vpnName);
+ return;
+ }
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Add BGPVPN: add bgpvpn failed for vpn : {} due to failure in acquiring lock", vpnName);
+ return;
+ }
// handle route-target(s)
List<String> inputRouteList = input.getRouteTargets();
List<String> inputImportRouteList = input.getImportTargets();
if (inputExportRouteList != null && !inputExportRouteList.isEmpty()) {
inputExportRouteSet.addAll(inputExportRouteList);
}
- List<String> importRouteTargets = new ArrayList<>();
- List<String> exportRouteTargets = new ArrayList<>();
- importRouteTargets.addAll(inputImportRouteSet);
- exportRouteTargets.addAll(inputExportRouteSet);
+ List<String> importRouteTargets = new ArrayList<>(inputImportRouteSet);
+ List<String> exportRouteTargets = new ArrayList<>(inputExportRouteSet);
+ boolean rdIrtErtStringsValid;
- List<String> rd = input.getRouteDistinguishers() != null
- ? input.getRouteDistinguishers() : new ArrayList<>();
+ List<String> rdList = input.getRouteDistinguishers();
- if (rd == null || rd.isEmpty()) {
- // generate new RD
- // TODO - commented out for now to avoid "Dead store to rd" violation.
- //rd = generateNewRD(input.getUuid());
- } else {
- String[] rdParams = rd.get(0).split(":");
+ if (rdList != null && !rdList.isEmpty()) {
+ // get the primary RD for vpn instance, if exist
+ rdIrtErtStringsValid =
+ !(input.getRouteDistinguishers().stream().anyMatch(rdStr -> rdStr.contains(" ")));
+ rdIrtErtStringsValid =
+ rdIrtErtStringsValid && !(importRouteTargets.stream().anyMatch(irtStr -> irtStr.contains(" ")));
+ rdIrtErtStringsValid =
+ rdIrtErtStringsValid && !(exportRouteTargets.stream().anyMatch(ertStr -> ertStr.contains(" ")));
+ if (!rdIrtErtStringsValid) {
+ LOG.error("Error encountered for BGPVPN {} with RD {} as RD/iRT/eRT contains whitespace "
+ + "characters", vpnName, input.getRouteDistinguishers());
+ return;
+ }
+ String primaryRd = neutronvpnUtils.getVpnRd(vpnName);
+ if (primaryRd == null) {
+ primaryRd = rdList.get(0);
+ }
+
+ String[] rdParams = primaryRd.split(":");
if (rdParams[0].trim().equals(adminRDValue)) {
LOG.error("AS specific part of RD should not be same as that defined by DC Admin. Error "
- + "encountered for BGPVPN {} with RD {}", vpnName, rd.get(0));
+ + "encountered for BGPVPN {} with RD {}", vpnName, primaryRd);
+ return;
+ }
+ String vpnWithSameRd = neutronvpnUtils.getVpnForRD(primaryRd);
+ if (vpnWithSameRd != null) {
+ LOG.error("Creation of L3VPN failed for VPN {} as another VPN {} with the same RD {} "
+ + "is already configured", vpnName, vpnWithSameRd, primaryRd);
return;
}
- List<String> existingRDs = neutronvpnUtils.getExistingRDs();
- if (!Collections.disjoint(existingRDs, rd)) {
- LOG.error("Failed to create VPN {} as another VPN with the same RD {} already exists.", vpnName,
- rd);
+ String existingOperationalVpn = neutronvpnUtils.getExistingOperationalVpn(primaryRd);
+ if (existingOperationalVpn != null) {
+ LOG.error("checkVpnCreation: Creation of L3VPN failed for VPN {} as another VPN {} with the "
+ + "same RD {} is still available.", vpnName, existingOperationalVpn, primaryRd);
return;
}
- List<Uuid> routersList = null;
- if (input.getRouters() != null && !input.getRouters().isEmpty()) {
- // try to take all routers
- routersList = input.getRouters();
+ List<Uuid> unpRtrs = neutronBgpvpnUtils.getUnprocessedRoutersForBgpvpn(input.getUuid());
+ List<Uuid> unpNets = neutronBgpvpnUtils.getUnprocessedNetworksForBgpvpn(input.getUuid());
+
+ // TODO: Currently handling routers and networks for backward compatibility. Below logic needs to be
+ // removed once updated to latest BGPVPN API's.
+ List<Uuid> inputRouters = input.getRouters();
+ if (inputRouters != null && !inputRouters.isEmpty()) {
+ if (unpRtrs != null) {
+ unpRtrs.addAll(inputRouters);
+ } else {
+ unpRtrs = new ArrayList<>(inputRouters);
+ }
}
- if (routersList != null && routersList.size() > NeutronConstants.MAX_ROUTERS_PER_BGPVPN) {
+ if (unpRtrs != null && unpRtrs.size() > NeutronConstants.MAX_ROUTERS_PER_BGPVPN) {
LOG.error("Creation of BGPVPN for rd {} failed: maximum allowed number of associated "
- + "routers is {}.", rd, NeutronConstants.MAX_ROUTERS_PER_BGPVPN);
+ + "routers is {}.", rdList, NeutronConstants.MAX_ROUTERS_PER_BGPVPN);
return;
}
- List<Uuid> networkList = null;
- if (input.getNetworks() != null && !input.getNetworks().isEmpty()) {
- networkList = input.getNetworks();
- }
- if (!rd.isEmpty()) {
- try {
- nvpnManager.createVpn(input.getUuid(), input.getName(), input.getTenantId(), rd,
- importRouteTargets, exportRouteTargets, routersList, networkList,
- false /*isL2Vpn*/, 0 /*l3vni*/);
- } catch (Exception e) {
- LOG.error("Creation of BGPVPN {} failed", vpnName, e);
+ List<Uuid> inputNetworks = input.getNetworks();
+ if (inputNetworks != null && !inputNetworks.isEmpty()) {
+ if (unpNets != null) {
+ unpNets.addAll(inputNetworks);
+ } else {
+ unpNets = new ArrayList<>(inputNetworks);
}
- } else {
- LOG.error("Create BgpVPN with id {} failed due to missing RD value", vpnName);
}
+ try {
+ nvpnManager.createVpn(input.getUuid(), input.getName(), input.getTenantId(), rdList,
+ importRouteTargets, exportRouteTargets, unpRtrs, unpNets, false /* isL2Vpn */,
+ 0 /* l3vni */);
+ neutronBgpvpnUtils.getUnProcessedRoutersMap().remove(input.getUuid());
+ neutronBgpvpnUtils.getUnProcessedNetworksMap().remove(input.getUuid());
+ } catch (Exception e) {
+ LOG.error("Creation of BGPVPN {} failed with error ", vpnName, e);
+ }
+ } else {
+ LOG.error("add: RD is absent for BGPVPN {}", vpnName);
}
- } else {
- LOG.warn("BGPVPN type for VPN {} is not L3", vpnName);
}
}
public void remove(InstanceIdentifier<Bgpvpn> identifier, Bgpvpn input) {
LOG.trace("Removing Bgpvpn : key: {}, value={}", identifier, input);
Uuid vpnId = input.getUuid();
- if (isBgpvpnTypeL3(input.getType())) {
+ String vpnName = vpnId.getValue();
+ if (!isBgpvpnTypeL3(input.getType())) {
+ LOG.warn("BGPVPN type for VPN {} is not L3", vpnName);
+ return;
+ }
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Remove BGPVPN: remove bgpvpn failed for vpn : {} due to failure in acquiring lock", vpnName);
+ return;
+ }
+ neutronBgpvpnUtils.getUnProcessedRoutersMap().remove(input.getUuid());
+ neutronBgpvpnUtils.getUnProcessedNetworksMap().remove(input.getUuid());
VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
if (vpnMap == null) {
LOG.error("Failed to handle BGPVPN Remove for VPN {} as that VPN is not configured"
- + " yet as a VPN Instance", vpnId.getValue());
+ + " yet as a VPN Instance", vpnName);
return;
}
nvpnManager.removeVpn(input.getUuid());
- // Release RD Id in pool
- List<String> rd = input.getRouteDistinguishers();
- if (rd == null || rd.isEmpty()) {
- int releasedId = neutronvpnUtils.releaseId(NeutronConstants.RD_IDPOOL_NAME, vpnId.getValue());
- if (releasedId == NeutronConstants.INVALID_ID) {
- LOG.error("NeutronBgpvpnChangeListener remove: Unable to release ID for key {}", vpnId.getValue());
- }
- }
- } else {
- LOG.warn("BGPVPN type for VPN {} is not L3", vpnId.getValue());
}
}
if (Objects.equals(original, update)) {
return;
}
- Uuid vpnId = update.getUuid();
- if (isBgpvpnTypeL3(update.getType())) {
- try {
- handleVpnInstanceUpdate(original.getUuid().getValue(), original.getRouteDistinguishers(),
- update.getRouteDistinguishers());
- } catch (UnsupportedOperationException e) {
- LOG.error("Error while processing Update Bgpvpn.", e);
+ String vpnName = update.getUuid().getValue();
+ if (!isBgpvpnTypeL3(update.getType())) {
+ LOG.warn("BGPVPN type for VPN {} is not L3", vpnName);
+ return;
+ }
+ boolean rdIrtErtStringsValid = true;
+ rdIrtErtStringsValid = rdIrtErtStringsValid
+ && !(update.getRouteDistinguishers().stream().anyMatch(rdStr -> rdStr.contains(" ")));
+ rdIrtErtStringsValid =
+ rdIrtErtStringsValid && !(update.getImportTargets().stream().anyMatch(irtStr -> irtStr.contains(" ")));
+ rdIrtErtStringsValid =
+ rdIrtErtStringsValid && !(update.getExportTargets().stream().anyMatch(ertStr -> ertStr.contains(" ")));
+ if (!rdIrtErtStringsValid) {
+ LOG.error("Error encountered for BGPVPN {} with RD {} as RD/iRT/eRT contains whitespace characters",
+ vpnName, update.getRouteDistinguishers());
+ return;
+ }
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Update VPN: update failed for vpn : {} due to failure in acquiring lock", vpnName);
return;
}
- List<Uuid> oldNetworks = original.getNetworks();
- List<Uuid> newNetworks = update.getNetworks();
+ handleVpnInstanceUpdate(original.getUuid().getValue(), original.getRouteDistinguishers(),
+ update.getRouteDistinguishers());
+
+ // TODO: Currently handling routers and networks for backward compatibility. Below logic needs to be
+ // removed once updated to latest BGPVPN API's.
+ Uuid vpnId = update.getUuid();
+ List<Uuid> oldNetworks = new ArrayList<>(original.getNetworks());
+ List<Uuid> newNetworks = new ArrayList<>(update.getNetworks());
handleNetworksUpdate(vpnId, oldNetworks, newNetworks);
+
List<Uuid> oldRouters = original.getRouters();
List<Uuid> newRouters = update.getRouters();
handleRoutersUpdate(vpnId, oldRouters, newRouters);
- } else {
- LOG.warn("BGPVPN type for VPN {} is not L3", vpnId.getValue());
+ } catch (UnsupportedOperationException e) {
+ LOG.error("Error while processing Update Bgpvpn.", e);
}
}
- protected void handleVpnInstanceUpdate(String vpnInstanceName,final List<String> originalRds,
- List<String> updateRDs) throws UnsupportedOperationException {
+ protected void handleVpnInstanceUpdate(String vpnInstanceName, final List<String> originalRds,
+ List<String> updateRDs) throws UnsupportedOperationException {
if (updateRDs == null || updateRDs.isEmpty()) {
return;
}
int oldRdsCount = originalRds.size();
for (String rd : originalRds) {
- //If the existing rd is not present in the updateRds list, not allow to process the updateRDs.
+ // If the existing rd is not present in the updateRds list, not allow to process the updateRDs.
if (!updateRDs.contains(rd)) {
LOG.error("The existing RD {} not present in the updatedRDsList:{}", rd, updateRDs);
throw new UnsupportedOperationException("The existing RD not present in the updatedRDsList");
nvpnManager.updateVpnInstanceWithRDs(vpnInstanceName, updateRDs);
}
- protected void handleNetworksUpdate(Uuid vpnId, List<Uuid> oldNetworks, List<Uuid> newNetworks) {
+ /**
+ * Handle networks update.
+ *
+ * @deprecated Retaining method for backward compatibility. Below method needs to be removed once
+ * updated to latest BGPVPN API's.
+ *
+ * @param vpnId the vpn id
+ * @param oldNetworks the old networks
+ * @param newNetworks the new networks
+ */
+ @Deprecated
+ private void handleNetworksUpdate(Uuid vpnId, List<Uuid> oldNetworks, List<Uuid> newNetworks) {
if (newNetworks != null && !newNetworks.isEmpty()) {
if (oldNetworks != null && !oldNetworks.isEmpty()) {
if (oldNetworks != newNetworks) {
}
}
- protected void handleRoutersUpdate(Uuid vpnId, List<Uuid> oldRouters, List<Uuid> newRouters) {
+ /**
+ * Handle routers update.
+ *
+ * @deprecated Retaining method for backward compatibility. Below method needs to be removed once
+ * updated to latest BGPVPN API's.
+ *
+ * @param vpnId the vpn id
+ * @param oldRouters the old routers
+ * @param newRouters the new routers
+ */
+ @Deprecated
+ private void handleRoutersUpdate(Uuid vpnId, List<Uuid> oldRouters, List<Uuid> newRouters) {
// for dualstack case we can associate with one VPN instance maximum 2 routers: one with
// only IPv4 ports and one with only IPv6 ports, or only one router with IPv4/IPv6 ports
// TODO: check router ports ethertype to follow this restriction
}
}
- private void createIdPool() {
- CreateIdPoolInput createPool = new CreateIdPoolInputBuilder().setPoolName(NeutronConstants.RD_IDPOOL_NAME)
- .setLow(NeutronConstants.RD_IDPOOL_START)
- .setHigh(new BigInteger(NeutronConstants.RD_IDPOOL_SIZE).longValue()).build();
- try {
- Future<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
- Collection<RpcError> rpcErrors = null;
- if (result != null && result.get() != null) {
- RpcResult<CreateIdPoolOutput> rpcResult = result.get();
- LOG.info("Created IdPool for Bgpvpn RD");
- if (rpcResult.isSuccessful()) {
- LOG.info("Created IdPool for Bgpvpn RD");
- return;
- }
- rpcErrors = rpcResult.getErrors();
- LOG.error("Failed to create ID pool for BGPVPN RD, result future returned {}", result);
- }
- LOG.error("createIdPool: Failed to create ID pool for BGPVPN RD, the call returned with RPC errors {}",
- rpcErrors != null ? rpcErrors : "RpcResult is null");
- } catch (InterruptedException | ExecutionException e) {
- LOG.error("Failed to create idPool for Bgpvpn RD", e);
- }
- }
-
private boolean validateRouteInfo(Uuid routerID) {
Uuid assocVPNId;
if ((assocVPNId = neutronvpnUtils.getVpnForRouter(routerID, true)) != null) {
}
return true;
}
-
-}
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2020 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.neutronvpn;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
+import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpn.network.association.rev190502.bgpvpn.network.associations.attributes.BgpvpnNetworkAssociations;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpn.network.association.rev190502.bgpvpn.network.associations.attributes.bgpvpn.network.associations.BgpvpnNetworkAssociation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class NeutronBgpvpnNetworkAssociationChangeListener
+ extends AbstractAsyncDataTreeChangeListener<BgpvpnNetworkAssociation> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronBgpvpnNetworkAssociationChangeListener.class);
+
+ private final NeutronvpnManager nvpnManager;
+ private final IdManagerService idManager;
+ private final NeutronvpnUtils neutronvpnUtils;
+ private final NeutronBgpvpnUtils neutronBgpvpnUtils;
+
+ @Inject
+ public NeutronBgpvpnNetworkAssociationChangeListener(final DataBroker dataBroker,
+ final NeutronvpnManager neutronvpnManager, final IdManagerService idManager,
+ final NeutronvpnUtils neutronvpnUtils, final NeutronBgpvpnUtils neutronBgpvpnUtils) {
+ super(dataBroker, LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Neutron.class).child(BgpvpnNetworkAssociations.class)
+ .child(BgpvpnNetworkAssociation.class),
+ Executors.newSingleThreadExecutor("NeutronBgpvpnNetworkAssociationChangeListener", LOG));
+
+ this.nvpnManager = neutronvpnManager;
+ this.idManager = idManager;
+ this.neutronvpnUtils = neutronvpnUtils;
+ this.neutronBgpvpnUtils = neutronBgpvpnUtils;
+ init();
+ }
+
+ public void init() {
+ LOG.info("{} init", getClass().getSimpleName());
+ }
+
+ @Override
+ @PreDestroy
+ public void close() {
+ super.close();
+ Executors.shutdownAndAwaitTermination(getExecutorService());
+ }
+
+ @Override
+ public void add(InstanceIdentifier<BgpvpnNetworkAssociation> identifier, BgpvpnNetworkAssociation input) {
+ LOG.trace("Adding Bgpvpn network association : key: {}, value={}", identifier, input);
+ Uuid vpnId = input.getBgpvpnId();
+ String vpnName = vpnId.getValue();
+ Uuid networkId = input.getNetworkId();
+ List<Uuid> networks = new ArrayList<>();
+ networks.add(networkId);
+
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Add network association: add association failed for vpn : {} and networkId: {} due to "
+ + "failure in acquiring lock", vpnName, networkId.getValue());
+ return;
+ }
+ VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(vpnId);
+ if (vpnInstance != null) {
+ List<String> errorMessages = nvpnManager.associateNetworksToVpn(vpnId, networks);
+ if (!errorMessages.isEmpty()) {
+ LOG.error("BgpvpnNetworkAssociation add: associate network id {} to vpn {} failed due to {}",
+ networkId.getValue(), vpnId.getValue(), errorMessages);
+ }
+ } else {
+ neutronBgpvpnUtils.addUnProcessedNetwork(vpnId, networkId);
+ }
+ }
+ }
+
+ @Override
+ public void update(InstanceIdentifier<BgpvpnNetworkAssociation> identifier, BgpvpnNetworkAssociation original,
+ BgpvpnNetworkAssociation update) {
+
+ }
+
+ @Override
+ public void remove(InstanceIdentifier<BgpvpnNetworkAssociation> identifier, BgpvpnNetworkAssociation input) {
+ LOG.trace("Removing Bgpvpn network association : key: {}, value={}", identifier, input);
+
+ Uuid vpnId = input.getBgpvpnId();
+ String vpnName = vpnId.getValue();
+ Uuid networkId = input.getNetworkId();
+ List<Uuid> networks = new ArrayList<>();
+ networks.add(networkId);
+
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Remove network association: remove association failed for vpn : {} and networkId: {} due "
+ + "to failure in acquiring lock", vpnName, networkId.getValue());
+ return;
+ }
+ neutronBgpvpnUtils.removeUnProcessedNetwork(vpnId, networkId);
+ VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(vpnId);
+ if (vpnInstance != null) {
+ List<String> errorMessages = nvpnManager.dissociateNetworksFromVpn(vpnId, networks);
+ if (!errorMessages.isEmpty()) {
+ LOG.error("BgpvpnNetworkAssociation remove: dissociate network id {} to vpn {} failed due to {}",
+ networkId.getValue(), vpnName, errorMessages);
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.neutronvpn;
+
+import java.util.concurrent.TimeUnit;
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.infrautils.utils.concurrent.Executors;
+import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
+import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.instances.VpnInstance;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpn.router.association.rev190502.bgpvpn.router.associations.attributes.BgpvpnRouterAssociations;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.bgpvpn.router.association.rev190502.bgpvpn.router.associations.attributes.bgpvpn.router.associations.BgpvpnRouterAssociation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class NeutronBgpvpnRouterAssociationChangeListener
+ extends AbstractAsyncDataTreeChangeListener<BgpvpnRouterAssociation> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronBgpvpnRouterAssociationChangeListener.class);
+
+ private final NeutronvpnManager nvpnManager;
+ private final IdManagerService idManager;
+ private final NeutronvpnUtils neutronvpnUtils;
+ private final NeutronBgpvpnUtils neutronBgpvpnUtils;
+
+ @Inject
+ public NeutronBgpvpnRouterAssociationChangeListener(final DataBroker dataBroker,
+ final NeutronvpnManager neutronvpnManager, final IdManagerService idManager,
+ final NeutronvpnUtils neutronvpnUtils, final NeutronBgpvpnUtils neutronBgpvpnUtils) {
+ super(dataBroker, LogicalDatastoreType.CONFIGURATION,
+ InstanceIdentifier.create(Neutron.class).child(BgpvpnRouterAssociations.class)
+ .child(BgpvpnRouterAssociation.class),
+ Executors.newSingleThreadExecutor("NeutronBgpvpnRouterAssociationChangeListener", LOG));
+
+ this.nvpnManager = neutronvpnManager;
+ this.idManager = idManager;
+ this.neutronvpnUtils = neutronvpnUtils;
+ this.neutronBgpvpnUtils = neutronBgpvpnUtils;
+ init();
+ }
+
+ public void init() {
+ LOG.info("{} init", getClass().getSimpleName());
+ }
+
+ @Override
+ @PreDestroy
+ public void close() {
+ super.close();
+ Executors.shutdownAndAwaitTermination(getExecutorService());
+ }
+
+ @Override
+ public void add(InstanceIdentifier<BgpvpnRouterAssociation> identifier, BgpvpnRouterAssociation input) {
+ LOG.trace("Adding Bgpvpn router association : key: {}, value={}", identifier, input);
+
+ Uuid vpnId = input.getBgpvpnId();
+ String vpnName = vpnId.getValue();
+ Uuid routerId = input.getRouterId();
+
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Add router association: add association failed for vpn : {} and routerId: {} due to "
+ + "failure in acquiring lock", vpnName, routerId.getValue());
+ return;
+ }
+ VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(vpnId);
+ if (vpnInstance != null) {
+ if (validateRouteInfo(routerId, vpnId)) {
+ nvpnManager.associateRouterToVpn(vpnId, routerId);
+ }
+ } else {
+ neutronBgpvpnUtils.addUnProcessedRouter(vpnId, routerId);
+ }
+ }
+ }
+
+ @Override
+ public void update(InstanceIdentifier<BgpvpnRouterAssociation> identifier, BgpvpnRouterAssociation original,
+ BgpvpnRouterAssociation update) {
+
+ }
+
+ @Override
+ public void remove(InstanceIdentifier<BgpvpnRouterAssociation> identifier, BgpvpnRouterAssociation input) {
+ LOG.trace("Removing Bgpvpn router association : key: {}, value={}", identifier, input);
+
+ Uuid vpnId = input.getBgpvpnId();
+ String vpnName = vpnId.getValue();
+ Uuid routerId = input.getRouterId();
+
+ NamedLocks<String> vpnLock = neutronBgpvpnUtils.getVpnLock();
+ try (AcquireResult lock = vpnLock.tryAcquire(vpnName, NeutronConstants.LOCK_WAIT_TIME, TimeUnit.SECONDS)) {
+ if (!lock.wasAcquired()) {
+ LOG.error("Remove router association: remove association failed for vpn : {} and routerId: {} due"
+ + " to failure in acquiring lock", vpnName, routerId.getValue());
+ return;
+ }
+ neutronBgpvpnUtils.removeUnProcessedRouter(vpnId, routerId);
+ VpnInstance vpnInstance = neutronvpnUtils.getVpnInstance(vpnId);
+ if (vpnInstance != null) {
+ nvpnManager.dissociateRouterFromVpn(vpnId, routerId);
+ }
+ }
+ }
+
+ private boolean validateRouteInfo(Uuid routerID, Uuid vpnId) {
+ Uuid assocVPNId;
+ if ((assocVPNId = neutronvpnUtils.getVpnForRouter(routerID, true)) != null) {
+ LOG.warn("VPN router association to VPN {} failed due to router {} already associated to another VPN {}",
+ vpnId.getValue(), routerID.getValue(), assocVPNId.getValue());
+ return false;
+ }
+ return true;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2020 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netvirt.neutronvpn;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+public class NeutronBgpvpnUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NeutronBgpvpnUtils.class);
+
+ private final ConcurrentHashMap<Uuid, List<Uuid>> unprocessedNetworksMap;
+ private final ConcurrentHashMap<Uuid, List<Uuid>> unprocessedRoutersMap;
+ private final NamedLocks<String> vpnLock;
+
+ @Inject
+ public NeutronBgpvpnUtils() {
+ unprocessedNetworksMap = new ConcurrentHashMap<>();
+ unprocessedRoutersMap = new ConcurrentHashMap<>();
+ vpnLock = new NamedLocks<>();
+ }
+
+ public void addUnProcessedNetwork(Uuid vpnId, Uuid networkId) {
+ LOG.trace("Adding Unprocessed Network to Bgpvpn : bgpvpnId: {}, networkId={}", vpnId.getValue(),
+ networkId.getValue());
+ List<Uuid> unProcessedNetworkIds = unprocessedNetworksMap.get(vpnId);
+ if (unProcessedNetworkIds == null) {
+ unProcessedNetworkIds = new ArrayList<>();
+ unProcessedNetworkIds.add(networkId);
+ unprocessedNetworksMap.putIfAbsent(vpnId, unProcessedNetworkIds);
+ } else {
+ if (!unProcessedNetworkIds.contains(networkId)) {
+ unProcessedNetworkIds.add(networkId);
+ }
+ }
+ }
+
+ public void removeUnProcessedNetwork(Uuid vpnId, Uuid networkId) {
+ LOG.trace("Removing Unprocessed Network to Bgpvpn : bgpvpnId: {}, networkId={}", vpnId.getValue(),
+ networkId.getValue());
+ List<Uuid> unProcessedNetworkIds = unprocessedNetworksMap.get(vpnId);
+ if (unProcessedNetworkIds != null) {
+ unProcessedNetworkIds.remove(networkId);
+ }
+ }
+
+ public void addUnProcessedRouter(Uuid vpnId, Uuid routerId) {
+ LOG.trace("Adding Unprocessed Router to Bgpvpn : bgpvpnId: {}, routerId={}", vpnId.getValue(),
+ routerId.getValue());
+ List<Uuid> unProcessedRouterIds = unprocessedRoutersMap.get(vpnId);
+ if (unProcessedRouterIds == null) {
+ unProcessedRouterIds = new ArrayList<>();
+ unProcessedRouterIds.add(routerId);
+ unprocessedRoutersMap.putIfAbsent(vpnId, unProcessedRouterIds);
+ } else {
+ if (!unProcessedRouterIds.contains(routerId)) {
+ unProcessedRouterIds.add(routerId);
+ }
+ }
+ }
+
+ public void removeUnProcessedRouter(Uuid vpnId, Uuid routerId) {
+ LOG.trace("Removing Unprocessed Router to Bgpvpn : bgpvpnId: {}, routerId={}", vpnId.getValue(),
+ routerId.getValue());
+ List<Uuid> unProcessedRouterIds = unprocessedRoutersMap.get(vpnId);
+ if (unProcessedRouterIds != null) {
+ unProcessedRouterIds.remove(routerId);
+ }
+ }
+
+ public NamedLocks<String> getVpnLock() {
+ return vpnLock;
+ }
+
+ public ConcurrentHashMap<Uuid, List<Uuid>> getUnProcessedRoutersMap() {
+ return unprocessedRoutersMap;
+ }
+
+ public ConcurrentHashMap<Uuid, List<Uuid>> getUnProcessedNetworksMap() {
+ return unprocessedNetworksMap;
+ }
+
+ public List<Uuid> getUnprocessedNetworksForBgpvpn(Uuid vpnId) {
+ return unprocessedNetworksMap.get(vpnId);
+ }
+
+ public List<Uuid> getUnprocessedRoutersForBgpvpn(Uuid vpnId) {
+ return unprocessedRoutersMap.get(vpnId);
+ }
+}