Use JvmGlobalLocks in vpnmanager
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnInstanceListener.java
index 900e3bdd7f89c92c60dcbe71caa2905d41e3272e..1bfd14307442c41437d6a7d8c9bef48cbfdcc99f 100644 (file)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.netvirt.vpnmanager;
 
+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 com.google.common.base.Optional;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
@@ -18,17 +22,21 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Callable;
+import java.util.concurrent.locks.ReentrantLock;
 import javax.annotation.PostConstruct;
 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.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.SingleTransactionDataBroker;
+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.TypedWriteTransaction;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
@@ -40,6 +48,7 @@ import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.genius.utils.SystemPropertyReader;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -77,12 +86,13 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
     private final VpnOpDataSyncer vpnOpDataNotifier;
     private final IMdsalApiManager mdsalManager;
     private final JobCoordinator jobCoordinator;
+    private final VpnUtil vpnUtil;
 
     @Inject
     public VpnInstanceListener(final DataBroker dataBroker, final IdManagerService idManager,
             final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
             final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager,
-            final JobCoordinator jobCoordinator) {
+            final JobCoordinator jobCoordinator, VpnUtil vpnUtil) {
         super(VpnInstance.class, VpnInstanceListener.class);
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
@@ -92,6 +102,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         this.vpnOpDataNotifier = vpnOpDataSyncer;
         this.mdsalManager = mdsalManager;
         this.jobCoordinator = jobCoordinator;
+        this.vpnUtil = vpnUtil;
     }
 
     @PostConstruct
@@ -133,12 +144,12 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             return;
         } else {
             jobCoordinator.enqueueJob("VPN-" + vpnName, () ->
-                Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+                Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
                     VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
                             .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
                     InstanceIdentifier<VpnInstanceOpDataEntry> id =
                             VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
-                    tx.merge(LogicalDatastoreType.OPERATIONAL, id, builder.build());
+                    tx.merge(id, builder.build());
 
                     LOG.info("{} call: Operational status set to PENDING_DELETE for vpn {} with rd {}",
                             LOGGING_PREFIX_DELETE, vpnName, primaryRd);
@@ -149,8 +160,17 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
     @Override
     protected void update(InstanceIdentifier<VpnInstance> identifier,
         VpnInstance original, VpnInstance update) {
-        LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}. Ignoring", identifier, update);
+        LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}.", identifier, update);
         String vpnName = update.getVpnInstanceName();
+        if (original.getIpv4Family() != null && update.getIpv4Family() != null
+                && original.getIpv4Family().getRouteDistinguisher() != null
+                && update.getIpv4Family().getRouteDistinguisher() != null
+                && original.getIpv4Family().getRouteDistinguisher().size()
+                !=  update.getIpv4Family().getRouteDistinguisher().size()) {
+            LOG.debug("VPN-UPDATE: VpnInstance:{} updated with new RDs: {} from old RDs: {}", vpnName,
+                    update.getIpv4Family().getRouteDistinguisher(),  original.getIpv4Family().getRouteDistinguisher());
+            vpnUtil.updateVpnInstanceWithRdList(vpnName, update.getIpv4Family().getRouteDistinguisher());
+        }
         vpnInterfaceManager.updateVpnInterfacesForUnProcessAdjancencies(vpnName);
     }
 
@@ -178,8 +198,8 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
             // to call the respective helpers.
             List<ListenableFuture<Void>> futures = new ArrayList<>(2);
-            futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(confTx -> {
-                ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(operTx ->
+            futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
+                ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, operTx ->
                         addVpnInstance(vpnInstance, confTx, operTx));
                 ListenableFutures.addErrorLogging(future, LOG, "{} call: error creating VPN {}", LOGGING_PREFIX_ADD,
                         vpnInstance.getVpnInstanceName());
@@ -194,22 +214,22 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void addVpnInstance(VpnInstance value, WriteTransaction writeConfigTxn,
-        WriteTransaction writeOperTxn) {
+    private void addVpnInstance(VpnInstance value, TypedWriteTransaction<Configuration> writeConfigTxn,
+            TypedWriteTransaction<Operational> writeOperTxn) {
         if (writeConfigTxn == null) {
-            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
                 addVpnInstance(value, tx, writeOperTxn)), LOG, "Error adding VPN instance {}", value);
             return;
         }
         if (writeOperTxn == null) {
-            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx ->
                 addVpnInstance(value, writeConfigTxn, tx)), LOG, "Error adding VPN instance {}", value);
             return;
         }
         VpnAfConfig config = value.getIpv4Family();
         String vpnInstanceName = value.getVpnInstanceName();
 
-        long vpnId = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
+        long vpnId = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME, vpnInstanceName);
         if (vpnId == 0) {
             LOG.error("{} addVpnInstance: Unable to fetch label from Id Manager. Bailing out of adding operational"
                     + " data for Vpn Instance {}", LOGGING_PREFIX_ADD, value.getVpnInstanceName());
@@ -221,16 +241,13 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance
             vpnInstanceToVpnId = VpnUtil.getVpnInstanceToVpnId(vpnInstanceName, vpnId, primaryRd);
 
-        writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
-            VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
-            vpnInstanceToVpnId, WriteTransaction.CREATE_MISSING_PARENTS);
+        writeConfigTxn.put(VpnOperDsUtils.getVpnInstanceToVpnIdIdentifier(vpnInstanceName),
+            vpnInstanceToVpnId, CREATE_MISSING_PARENTS);
 
         VpnIds vpnIdToVpnInstance = VpnUtil.getVpnIdToVpnInstance(vpnId, value.getVpnInstanceName(),
             primaryRd, VpnUtil.isBgpVpn(vpnInstanceName, primaryRd));
 
-        writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION,
-            VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId),
-            vpnIdToVpnInstance, WriteTransaction.CREATE_MISSING_PARENTS);
+        writeConfigTxn.put(VpnUtil.getVpnIdToVpnInstanceIdentifier(vpnId), vpnIdToVpnInstance, CREATE_MISSING_PARENTS);
 
         try {
             String cachedTransType = fibManager.getConfTransType();
@@ -271,7 +288,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
                 if (vpnTargetList != null) {
                     for (VpnTarget vpnTarget : vpnTargetList) {
                         VpnTargetBuilder vpnTargetBuilder =
-                            new VpnTargetBuilder().setKey(new VpnTargetKey(vpnTarget.getKey().getVrfRTValue()))
+                            new VpnTargetBuilder().withKey(new VpnTargetKey(vpnTarget.key().getVrfRTValue()))
                                 .setVrfRTType(org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
                                     .instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget.VrfRTType
                                     .forValue(vpnTarget.getVrfRTType().getIntValue())).setVrfRTValue(
@@ -288,9 +305,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         } else {
             builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.VPN);
         }
-        writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL,
-            VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd),
-            builder.build(), true);
+        writeOperTxn.merge(VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd), builder.build(), CREATE_MISSING_PARENTS);
         LOG.info("{} addVpnInstance: VpnInstanceOpData populated successfully for vpn {} rd {}", LOGGING_PREFIX_ADD,
                 vpnInstanceName, primaryRd);
     }
@@ -321,15 +336,15 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
                 vpnInterfaceManager.vpnInstanceIsReady(vpnName);
             }
             log.info("{} onSuccess: Vpn Instance Op Data addition for {} successful.", LOGGING_PREFIX_ADD, vpnName);
-            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(dataBroker,
+            VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(
                     VpnUtil.getPrimaryRd(vpnInstance));
 
             // bind service on each tunnel interface
             //TODO (KIRAN): Add a new listener to handle creation of new DC-GW binding and deletion of existing DC-GW.
             if (VpnUtil.isL3VpnOverVxLan(vpnInstance.getL3vni())) { //Handled for L3VPN Over VxLAN
                 for (String tunnelInterfaceName: getDcGatewayTunnelInterfaceNameList()) {
-                    VpnUtil.bindService(vpnInstance.getVpnInstanceName(), tunnelInterfaceName, dataBroker,
-                            true/*isTunnelInterface*/, jobCoordinator);
+                    vpnUtil.bindService(vpnInstance.getVpnInstanceName(), tunnelInterfaceName,
+                            true/*isTunnelInterface*/);
                 }
 
                 // install flow
@@ -359,7 +374,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         @SuppressWarnings("checkstyle:IllegalCatch")
         private boolean addBgpVrf() {
             VpnAfConfig config = vpnInstance.getIpv4Family();
-            String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
+            String primaryRd = vpnUtil.getPrimaryRd(vpnName);
             List<VpnTarget> vpnTargetList = config.getVpnTargets().getVpnTarget();
 
             if (vpnTargetList == null) {
@@ -367,8 +382,13 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
                         this.vpnName, primaryRd);
                 return false;
             }
-            synchronized (vpnName.intern()) {
+            // FIXME: separate out to somehow?
+            final ReentrantLock lock = JvmGlobalLocks.getLockForString(vpnName);
+            lock.lock();
+            try {
                 fibManager.addVrfTable(primaryRd, null);
+            } finally {
+                lock.unlock();
             }
             vpnInterfaceManager.handleVpnsExportingRoutes(this.vpnName, primaryRd);
             return true;
@@ -394,6 +414,7 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         }
     }
 
+    @Nullable
     protected VpnInstanceOpDataEntry getVpnInstanceOpData(String rd) {
         InstanceIdentifier<VpnInstanceOpDataEntry> id = VpnUtil.getVpnInstanceOpDataIdentifier(rd);
         try {
@@ -406,54 +427,50 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
 
     private List<String> getDcGatewayTunnelInterfaceNameList() {
         List<String> tunnelInterfaceNameList = new ArrayList<>();
-
-        InstanceIdentifier<DcGatewayIpList> dcGatewayIpListInstanceIdentifier = InstanceIdentifier
-                .create(DcGatewayIpList.class);
-        Optional<DcGatewayIpList> dcGatewayIpListOptional = VpnUtil.read(dataBroker,
-                LogicalDatastoreType.CONFIGURATION, dcGatewayIpListInstanceIdentifier);
-        if (!dcGatewayIpListOptional.isPresent()) {
-            LOG.info("No DC gateways configured.");
-            return tunnelInterfaceNameList;
-        }
-        List<DcGatewayIp> dcGatewayIps = dcGatewayIpListOptional.get().getDcGatewayIp();
-
-        InstanceIdentifier<ExternalTunnelList> externalTunnelListId = InstanceIdentifier
-                .create(ExternalTunnelList.class);
-
-        Optional<ExternalTunnelList> externalTunnelListOptional = VpnUtil.read(dataBroker,
-                LogicalDatastoreType.OPERATIONAL, externalTunnelListId);
-        if (externalTunnelListOptional.isPresent()) {
-            List<ExternalTunnel> externalTunnels = externalTunnelListOptional.get().getExternalTunnel();
-
-            List<String> externalTunnelIpList = new ArrayList<>();
-            for (ExternalTunnel externalTunnel: externalTunnels) {
-                externalTunnelIpList.add(externalTunnel.getDestinationDevice());
-            }
-
-            List<String> dcGatewayIpList = new ArrayList<>();
-            for (DcGatewayIp dcGatewayIp: dcGatewayIps) {
-                dcGatewayIpList.add(dcGatewayIp.getIpAddress().getIpv4Address().toString());
+        try {
+            InstanceIdentifier<DcGatewayIpList> dcGatewayIpListInstanceIdentifier = InstanceIdentifier
+                    .create(DcGatewayIpList.class);
+            Optional<DcGatewayIpList> dcGatewayIpListOptional = SingleTransactionDataBroker.syncReadOptional(
+                    dataBroker, LogicalDatastoreType.CONFIGURATION, dcGatewayIpListInstanceIdentifier);
+            if (!dcGatewayIpListOptional.isPresent()) {
+                LOG.info("No DC gateways configured.");
+                return tunnelInterfaceNameList;
             }
-
-            // Find all externalTunnelIps present in dcGateWayIpList
-            List<String> externalTunnelIpsInDcGatewayIpList = new ArrayList<>();
-            for (String externalTunnelIp: externalTunnelIpList) {
-                for (String dcGateWayIp: dcGatewayIpList) {
-                    if (externalTunnelIp.contentEquals(dcGateWayIp)) {
-                        externalTunnelIpsInDcGatewayIpList.add(externalTunnelIp);
+            List<DcGatewayIp> dcGatewayIps = dcGatewayIpListOptional.get().nonnullDcGatewayIp();
+            InstanceIdentifier<ExternalTunnelList> externalTunnelListId = InstanceIdentifier
+                    .create(ExternalTunnelList.class);
+            Optional<ExternalTunnelList> externalTunnelListOptional = SingleTransactionDataBroker.syncReadOptional(
+                    dataBroker, LogicalDatastoreType.OPERATIONAL, externalTunnelListId);
+            if (externalTunnelListOptional.isPresent()) {
+                List<ExternalTunnel> externalTunnels = externalTunnelListOptional.get().nonnullExternalTunnel();
+                List<String> externalTunnelIpList = new ArrayList<>();
+                for (ExternalTunnel externalTunnel: externalTunnels) {
+                    externalTunnelIpList.add(externalTunnel.getDestinationDevice());
+                }
+                List<String> dcGatewayIpList = new ArrayList<>();
+                for (DcGatewayIp dcGatewayIp: dcGatewayIps) {
+                    dcGatewayIpList.add(dcGatewayIp.getIpAddress().getIpv4Address().toString());
+                }
+                // Find all externalTunnelIps present in dcGateWayIpList
+                List<String> externalTunnelIpsInDcGatewayIpList = new ArrayList<>();
+                for (String externalTunnelIp: externalTunnelIpList) {
+                    for (String dcGateWayIp: dcGatewayIpList) {
+                        if (externalTunnelIp.contentEquals(dcGateWayIp)) {
+                            externalTunnelIpsInDcGatewayIpList.add(externalTunnelIp);
+                        }
                     }
                 }
-            }
-
-
-            for (String externalTunnelIpsInDcGatewayIp: externalTunnelIpsInDcGatewayIpList) {
-                for (ExternalTunnel externalTunnel: externalTunnels) {
-                    if (externalTunnel.getDestinationDevice().contentEquals(externalTunnelIpsInDcGatewayIp)) {
-                        tunnelInterfaceNameList.add(externalTunnel.getTunnelInterfaceName());
+                for (String externalTunnelIpsInDcGatewayIp: externalTunnelIpsInDcGatewayIpList) {
+                    for (ExternalTunnel externalTunnel: externalTunnels) {
+                        if (externalTunnel.getDestinationDevice().contentEquals(externalTunnelIpsInDcGatewayIp)) {
+                            tunnelInterfaceNameList.add(externalTunnel.getTunnelInterfaceName());
+                        }
                     }
                 }
-            }
 
+            }
+        } catch (ReadFailedException e) {
+            LOG.error("getDcGatewayTunnelInterfaceNameList: Failed to read data store");
         }
         return tunnelInterfaceNameList;
     }