Use JvmGlobalLocks in neutronmanager
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronvpnManager.java
index 5fdd9231c0e5ebad3655b97667a4ec7605da0186..cb943282bdd575366907e210ea85d4639bba01aa 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.netvirt.neutronvpn;
 import static java.util.Collections.singletonList;
 import static org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker.syncReadOptional;
 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
+import static org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils.requireNonNullElse;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -35,8 +36,8 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.PreDestroy;
@@ -45,13 +46,16 @@ import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
-import org.opendaylight.genius.infra.Datastore;
+import org.opendaylight.genius.infra.Datastore.Configuration;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
 import org.opendaylight.genius.infra.TypedWriteTransaction;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.utils.JvmGlobalLocks;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.KeyedLocks;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -131,10 +135,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpnBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpnBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterInterfacesMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
@@ -160,6 +160,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.A
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.BgpvpnVni;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.OperationalPortStatus;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.Features;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.Feature;
@@ -214,7 +215,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             final VpnRpcService vpnRpcSrv, final IElanService elanService,
             final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener,
             final NeutronvpnConfig neutronvpnConfig, final IVpnManager vpnManager,
-            final JobCoordinator jobCoordinator, final NeutronvpnUtils neutronvpnUtils) {
+            final JobCoordinator jobCoordinator,
+            final NeutronvpnUtils neutronvpnUtils) throws TransactionCommitFailedException {
         this.dataBroker = dataBroker;
         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
         notificationPublishService = notiPublishService;
@@ -237,15 +239,25 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         LOG.info("{} close", getClass().getSimpleName());
     }
 
-    private void configureFeatures() {
+    private void configureFeatures() throws TransactionCommitFailedException {
         InstanceIdentifier<Feature> iid = InstanceIdentifier.builder(
                         Neutron.class).child(Features.class).child(
                         Feature.class, new FeatureKey(OperationalPortStatus.class)).build();
         Feature feature = new FeatureBuilder().withKey(new FeatureKey(OperationalPortStatus.class)).build();
         try {
             SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, iid, feature);
-        } catch (TransactionCommitFailedException e) {
-            LOG.warn("Error configuring feature {}", feature, e);
+        } catch (OptimisticLockFailedException e) {
+            LOG.debug("Optimistic lock failed exception while configuring feature {}", feature, e);
+        }
+        InstanceIdentifier<Feature> bgpvpnVniIid = InstanceIdentifier.builder(
+                Neutron.class).child(Features.class).child(
+                Feature.class, new FeatureKey(BgpvpnVni.class)).build();
+        Feature bgpvpnVniFeature = new FeatureBuilder().withKey(new FeatureKey(BgpvpnVni.class)).build();
+        try {
+            SingleTransactionDataBroker.syncWrite(
+                    dataBroker, LogicalDatastoreType.OPERATIONAL, bgpvpnVniIid, bgpvpnVniFeature);
+        } catch (OptimisticLockFailedException e) {
+            LOG.debug("Optimistic lock failed exception while configuring feature {}", bgpvpnVniFeature, e);
         }
     }
 
@@ -256,10 +268,12 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void createSubnetmapNode(Uuid subnetId, String subnetIp, Uuid tenantId, Uuid networkId,
-                                       NetworkAttributes.NetworkType networkType, long segmentationId) {
+                                       @Nullable NetworkAttributes.NetworkType networkType, long segmentationId) {
         try {
             InstanceIdentifier<Subnetmap> subnetMapIdentifier = NeutronvpnUtils.buildSubnetMapIdentifier(subnetId);
-            synchronized (subnetId.getValue().intern()) {
+            final ReentrantLock lock = lockForUuid(subnetId);
+            lock.lock();
+            try {
                 LOG.info("createSubnetmapNode: subnet ID {}", subnetId.toString());
                 Optional<Subnetmap> sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
                         LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
@@ -275,6 +289,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     subnetId.getValue());
                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
                         subnetMapIdentifier, subnetmapBuilder.build());
+            } finally {
+                lock.unlock();
             }
         } catch (TransactionCommitFailedException | ReadFailedException e) {
             LOG.error("createSubnetmapNode: Creating subnetmap node failed for subnet {}", subnetId.getValue());
@@ -289,206 +305,215 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId, Uuid internetvpnId) {
-        Subnetmap subnetmap = null;
-        SubnetmapBuilder builder = null;
+    @Nullable
+    protected Subnetmap updateSubnetNode(Uuid subnetId, @Nullable Uuid routerId, Uuid vpnId,
+            @Nullable Uuid internetvpnId) {
         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
                 .build();
+        final ReentrantLock lock = lockForUuid(subnetId);
+        lock.lock();
         try {
-            synchronized (subnetId.getValue().intern()) {
-                Optional<Subnetmap> sn =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                id);
-                if (sn.isPresent()) {
-                    builder = new SubnetmapBuilder(sn.get());
-                    LOG.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
-                } else {
-                    LOG.error("subnetmap node for subnet {} does not exist, returning", subnetId.getValue());
-                    return null;
-                }
-                if (routerId != null) {
-                    builder.setRouterId(routerId);
-                }
-                if (vpnId != null) {
-                    builder.setVpnId(vpnId);
-                }
+            Optional<Subnetmap> sn =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+            if (!sn.isPresent()) {
+                LOG.error("subnetmap node for subnet {} does not exist, returning", subnetId.getValue());
+                return null;
+            }
+            LOG.debug("updating existing subnetmap node for subnet ID {}", subnetId.getValue());
+            SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
+            if (routerId != null) {
+                builder.setRouterId(routerId);
+            }
+            if (vpnId != null) {
+                builder.setVpnId(vpnId);
+            }
+            if (NeutronvpnUtils.getIpVersionFromString(sn.get().getSubnetIp()) == IpVersionChoice.IPV6) {
                 builder.setInternetVpnId(internetvpnId);
-
-                subnetmap = builder.build();
-                LOG.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
-                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
             }
+            Subnetmap subnetmap = builder.build();
+            LOG.debug("Creating/Updating subnetMap node: {} ", subnetId.getValue());
+            SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
+            return subnetmap;
         } catch (ReadFailedException | TransactionCommitFailedException e) {
             LOG.error("Subnet map update failed for node {}", subnetId.getValue(), e);
+            return null;
+        } finally {
+            lock.unlock();
         }
-        return subnetmap;
     }
 
-    protected void updateSubnetNodeWithFixedIp(Uuid subnetId, Uuid routerId,
-                                               Uuid routerInterfacePortId, String fixedIp,
-                                               String routerIntfMacAddress, Uuid vpnId) {
-        Subnetmap subnetmap = null;
-        SubnetmapBuilder builder = null;
+    protected void updateSubnetNodeWithFixedIp(Uuid subnetId, @Nullable Uuid routerId,
+                                               @Nullable Uuid routerInterfacePortId, @Nullable String fixedIp,
+                                               @Nullable String routerIntfMacAddress, @Nullable Uuid vpnId) {
         InstanceIdentifier<Subnetmap> id =
-            InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
+                InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
+        final ReentrantLock lock = lockForUuid(subnetId);
+        lock.lock();
         try {
-            synchronized (subnetId.getValue().intern()) {
-                Optional<Subnetmap> sn =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                id);
-                if (sn.isPresent()) {
-                    builder = new SubnetmapBuilder(sn.get());
-                    LOG.debug("WithRouterFixedIP: Updating existing subnetmap node for subnet ID {}",
-                        subnetId.getValue());
-                } else {
-                    LOG.error("WithRouterFixedIP: subnetmap node for subnet {} does not exist, returning ",
-                        subnetId.getValue());
-                    return;
-                }
-                builder.setRouterId(routerId);
-                builder.setRouterInterfacePortId(routerInterfacePortId);
-                builder.setRouterIntfMacAddress(routerIntfMacAddress);
-                builder.setRouterInterfaceFixedIp(fixedIp);
-                if (vpnId != null) {
-                    builder.setVpnId(vpnId);
-                }
-                subnetmap = builder.build();
-                LOG.debug("WithRouterFixedIP Creating/Updating subnetMap node for Router FixedIp: {} ",
+            Optional<Subnetmap> sn =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+            if (!sn.isPresent()) {
+                LOG.error("WithRouterFixedIP: subnetmap node for subnet {} does not exist, returning ",
                     subnetId.getValue());
-                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
+                return;
             }
+            LOG.debug("WithRouterFixedIP: Updating existing subnetmap node for subnet ID {}",
+                subnetId.getValue());
+            SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
+            builder.setRouterId(routerId);
+            builder.setRouterInterfacePortId(routerInterfacePortId);
+            builder.setRouterIntfMacAddress(routerIntfMacAddress);
+            builder.setRouterInterfaceFixedIp(fixedIp);
+            if (vpnId != null) {
+                builder.setVpnId(vpnId);
+            }
+            Subnetmap subnetmap = builder.build();
+            LOG.debug("WithRouterFixedIP Creating/Updating subnetMap node for Router FixedIp: {} ",
+                subnetId.getValue());
+            SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
         } catch (ReadFailedException | TransactionCommitFailedException e) {
             LOG.error("WithRouterFixedIP: subnet map for Router FixedIp failed for node {}",
                 subnetId.getValue(), e);
+        } finally {
+            lock.unlock();
         }
     }
 
-    protected Subnetmap updateSubnetmapNodeWithPorts(Uuid subnetId, Uuid portId, Uuid directPortId) {
+    protected Subnetmap updateSubnetmapNodeWithPorts(Uuid subnetId, @Nullable Uuid portId,
+            @Nullable Uuid directPortId) {
         Subnetmap subnetmap = null;
         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
                 new SubnetmapKey(subnetId)).build();
         LOG.info("updateSubnetmapNodeWithPorts : subnetId {}, subnetMapId {}", subnetId.toString(), id.toString());
+        final ReentrantLock lock = lockForUuid(subnetId);
+        lock.lock();
         try {
-            synchronized (subnetId.getValue().intern()) {
-                Optional<Subnetmap> sn =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                id);
-                if (sn.isPresent()) {
-                    SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
-                    if (null != portId) {
-                        List<Uuid> portList = builder.getPortList();
-                        if (null == portList) {
-                            portList = new ArrayList<>();
-                        }
-                        portList.add(portId);
-                        builder.setPortList(portList);
-                        LOG.debug("updateSubnetmapNodeWithPorts: Updating existing subnetmap node {} with port {}",
-                            subnetId.getValue(), portId.getValue());
+            Optional<Subnetmap> sn =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                        id);
+            if (sn.isPresent()) {
+                SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
+                if (null != portId) {
+                    List<Uuid> portList = builder.getPortList();
+                    if (null == portList) {
+                        portList = new ArrayList<>();
                     }
-                    if (null != directPortId) {
-                        List<Uuid> directPortList = builder.getDirectPortList();
-                        if (null == directPortList) {
-                            directPortList = new ArrayList<>();
-                        }
-                        directPortList.add(directPortId);
-                        builder.setDirectPortList(directPortList);
-                        LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
-                                directPortId.getValue());
+                    portList.add(portId);
+                    builder.setPortList(portList);
+                    LOG.debug("updateSubnetmapNodeWithPorts: Updating existing subnetmap node {} with port {}",
+                        subnetId.getValue(), portId.getValue());
+                }
+                if (null != directPortId) {
+                    List<Uuid> directPortList = builder.getDirectPortList();
+                    if (null == directPortList) {
+                        directPortList = new ArrayList<>();
                     }
-                    subnetmap = builder.build();
-                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
-                            subnetmap);
-                } else {
-                    LOG.info("updateSubnetmapNodeWithPorts: Subnetmap node is not ready {}, put port {} in unprocessed "
-                        + "cache ", subnetId.getValue(), portId.getValue());
-                    unprocessedPortsMap.put(portId, subnetId);
+                    directPortList.add(directPortId);
+                    builder.setDirectPortList(directPortList);
+                    LOG.debug("Updating existing subnetmap node {} with port {}", subnetId.getValue(),
+                        directPortId.getValue());
                 }
+                subnetmap = builder.build();
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
+                    subnetmap);
+            } else {
+                LOG.info("updateSubnetmapNodeWithPorts: Subnetmap node is not ready {}, put port {} in unprocessed "
+                        + "cache ", subnetId.getValue(), portId.getValue());
+                unprocessedPortsMap.put(portId, subnetId);
             }
         } catch (ReadFailedException | TransactionCommitFailedException e) {
             LOG.error("Updating port list of a given subnetMap failed for node: {}", subnetId.getValue(), e);
+        } finally {
+            lock.unlock();
         }
         return subnetmap;
     }
 
-    protected Subnetmap removeFromSubnetNode(Uuid subnetId, Uuid networkId, Uuid routerId,
-                                            Uuid vpnId, Uuid portId) {
+    protected Subnetmap removeFromSubnetNode(Uuid subnetId, @Nullable Uuid networkId, @Nullable Uuid routerId,
+                                            Uuid vpnId, @Nullable Uuid portId) {
         Subnetmap subnetmap = null;
         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
                 .child(Subnetmap.class, new SubnetmapKey(subnetId))
                 .build();
+        final ReentrantLock lock = lockForUuid(subnetId);
+        lock.lock();
         try {
-            synchronized (subnetId.getValue().intern()) {
-                Optional<Subnetmap> sn =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                id);
-                if (sn.isPresent()) {
-                    SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
-                    if (routerId != null) {
-                        builder.setRouterId(null);
-                    }
-                    if (networkId != null) {
-                        builder.setNetworkId(null);
-                    }
-                    if (vpnId != null) {
-                        builder.setVpnId(null);
-                    }
-                    builder.setInternetVpnId(null);
-                    if (portId != null && builder.getPortList() != null) {
-                        List<Uuid> portList = builder.getPortList();
-                        portList.remove(portId);
-                        builder.setPortList(portList);
-                    }
-
-                    subnetmap = builder.build();
-                    LOG.debug("Removing from existing subnetmap node: {} ", subnetId.getValue());
-                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
-                            subnetmap);
-                } else {
-                    LOG.warn("removing from non-existing subnetmap node: {} ", subnetId.getValue());
+            Optional<Subnetmap> sn =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                        id);
+            if (sn.isPresent()) {
+                SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
+                if (routerId != null) {
+                    builder.setRouterId(null);
                 }
+                if (networkId != null) {
+                    builder.setNetworkId(null);
+                }
+                if (vpnId != null) {
+                    builder.setVpnId(null);
+                }
+                builder.setInternetVpnId(null);
+                if (portId != null && builder.getPortList() != null) {
+                    List<Uuid> portList = builder.getPortList();
+                    portList.remove(portId);
+                    builder.setPortList(portList);
+                }
+
+                subnetmap = builder.build();
+                LOG.debug("Removing from existing subnetmap node: {} ", subnetId.getValue());
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
+                    subnetmap);
+            } else {
+                LOG.warn("removing from non-existing subnetmap node: {} ", subnetId.getValue());
             }
         } catch (ReadFailedException | TransactionCommitFailedException e) {
             LOG.error("Removal from subnetmap failed for node: {}", subnetId.getValue());
+        } finally {
+            lock.unlock();
         }
         return subnetmap;
     }
 
-    protected Subnetmap removePortsFromSubnetmapNode(Uuid subnetId, Uuid portId, Uuid directPortId) {
+    @Nullable
+    protected Subnetmap removePortsFromSubnetmapNode(Uuid subnetId, @Nullable Uuid portId,
+            @Nullable Uuid directPortId) {
         Subnetmap subnetmap = null;
         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
                 new SubnetmapKey(subnetId)).build();
+        final ReentrantLock lock = lockForUuid(subnetId);
+        lock.lock();
         try {
-            synchronized (subnetId.getValue().intern()) {
-                Optional<Subnetmap> sn =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                id);
-                if (sn.isPresent()) {
-                    SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
-                    if (null != portId && null != builder.getPortList()) {
-                        List<Uuid> portList = builder.getPortList();
-                        portList.remove(portId);
-                        builder.setPortList(portList);
-                        LOG.debug("Removing port {} from existing subnetmap node: {} ", portId.getValue(),
-                                subnetId.getValue());
-                    }
-                    if (null != directPortId && null != builder.getDirectPortList()) {
-                        List<Uuid> directPortList = builder.getDirectPortList();
-                        directPortList.remove(directPortId);
-                        builder.setDirectPortList(directPortList);
-                        LOG.debug("Removing direct port {} from existing subnetmap node: {} ", directPortId
-                                .getValue(), subnetId.getValue());
-                    }
-                    subnetmap = builder.build();
-                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
-                            subnetmap);
-                } else {
-                    LOG.info("Trying to remove port from non-existing subnetmap node {}", subnetId.getValue());
+            Optional<Subnetmap> sn =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                        id);
+            if (sn.isPresent()) {
+                SubnetmapBuilder builder = new SubnetmapBuilder(sn.get());
+                if (null != portId && null != builder.getPortList()) {
+                    List<Uuid> portList = builder.getPortList();
+                    portList.remove(portId);
+                    builder.setPortList(portList);
+                    LOG.debug("Removing port {} from existing subnetmap node: {} ", portId.getValue(),
+                        subnetId.getValue());
+                }
+                if (null != directPortId && null != builder.getDirectPortList()) {
+                    List<Uuid> directPortList = builder.getDirectPortList();
+                    directPortList.remove(directPortId);
+                    builder.setDirectPortList(directPortList);
+                    LOG.debug("Removing direct port {} from existing subnetmap node: {} ", directPortId
+                        .getValue(), subnetId.getValue());
                 }
+                subnetmap = builder.build();
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
+                    subnetmap);
+            } else {
+                LOG.info("Trying to remove port from non-existing subnetmap node {}", subnetId.getValue());
             }
         } catch (ReadFailedException | TransactionCommitFailedException e) {
             LOG.error("Removing a port from port list of a subnetmap failed for node: {}",
                     subnetId.getValue(), e);
+        } finally {
+            lock.unlock();
         }
         return subnetmap;
     }
@@ -499,13 +524,14 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         InstanceIdentifier<Subnetmap> subnetMapIdentifier =
                 InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
         LOG.debug("removing subnetMap node: {} ", subnetId.getValue());
+        final ReentrantLock lock = lockForUuid(subnetId);
+        lock.lock();
         try {
-            synchronized (subnetId.getValue().intern()) {
-                SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                        subnetMapIdentifier);
-            }
+            SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
         } catch (TransactionCommitFailedException e) {
             LOG.error("Delete subnetMap node failed for subnet : {} ", subnetId.getValue());
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -640,7 +666,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected void updateVpnMaps(Uuid vpnId, String name, Uuid router, Uuid tenantId, List<Uuid> networks) {
+    protected void updateVpnMaps(Uuid vpnId, @Nullable String name, @Nullable Uuid router, @Nullable Uuid tenantId,
+            @Nullable List<Uuid> networks) {
         VpnMapBuilder builder;
         boolean isLockAcquired = false;
         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
@@ -695,7 +722,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    private void clearFromVpnMaps(Uuid vpnId, Uuid routerId, List<Uuid> networkIds) {
+    private void clearFromVpnMaps(Uuid vpnId, @Nullable Uuid routerId, @Nullable List<Uuid> networkIds) {
         boolean isLockAcquired = false;
         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
                 .child(VpnMap.class, new VpnMapKey(vpnId))
@@ -789,15 +816,15 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     protected Adjacencies createPortIpAdjacencies(Port port, Boolean isRouterInterface,
-                                                  TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn,
-                                                  Subnetmap sn, VpnInterface vpnIface) {
+                                                  TypedWriteTransaction<Configuration> wrtConfigTxn,
+                                                  @Nullable Subnetmap sn, @Nullable VpnInterface vpnIface) {
         List<Adjacency> adjList = new ArrayList<>();
         if (vpnIface != null) {
             adjList = vpnIface.augmentation(Adjacencies.class).getAdjacency();
         }
         String infName = port.getUuid().getValue();
         LOG.trace("neutronVpnManager: create config adjacencies for Port: {}", infName);
-        for (FixedIps ip : port.getFixedIps()) {
+        for (FixedIps ip : requireNonNullElse(port.getFixedIps(), Collections.<FixedIps>emptyList())) {
             String ipValue = ip.getIpAddress().stringValue();
             String ipPrefix = ip.getIpAddress().getIpv4Address() != null ? ipValue + "/32" : ipValue + "/128";
             if (sn != null && !FibHelper.doesPrefixBelongToSubnet(ipPrefix, sn.getSubnetIp(), false)) {
@@ -839,19 +866,21 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     protected void createVpnInterface(Collection<Uuid> vpnIds, Port port,
-                                      TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
+                                      @Nullable TypedWriteTransaction<Configuration> wrtConfigTxn) {
         boolean isRouterInterface = false;
         if (port.getDeviceOwner() != null) {
             isRouterInterface = NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(port.getDeviceOwner());
         }
-        Adjacencies adjs = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn, null, null);
         String infName = port.getUuid().getValue();
+        // Handling cluster reboot scenario where VpnInterface already exists in datastore.
+        VpnInterface vpnIface = VpnHelper.getVpnInterface(dataBroker, infName);
+        Adjacencies adjs = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn, null, vpnIface);
         LOG.trace("createVpnInterface for Port: {}, isRouterInterface: {}", infName, isRouterInterface);
         writeVpnInterfaceToDs(vpnIds, infName, adjs, port.getNetworkId(), isRouterInterface, wrtConfigTxn);
     }
 
     protected void withdrawPortIpFromVpnIface(Uuid vpnId, Uuid internetVpnId,
-                       Port port, Subnetmap sn, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
+                       Port port, Subnetmap sn, TypedWriteTransaction<Configuration> wrtConfigTxn) {
         String infName = port.getUuid().getValue();
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
         Optional<VpnInterface> optionalVpnInterface = null;
@@ -870,7 +899,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
         LOG.trace("withdraw adjacencies for Port: {} subnet {}", port.getUuid().getValue(),
                 sn != null ? sn.getSubnetIp() : "null");
-        List<Adjacency> vpnAdjsList = optionalVpnInterface.get().augmentation(Adjacencies.class).getAdjacency();
+        List<Adjacency> vpnAdjsList =
+            requireNonNullElse(optionalVpnInterface.get().augmentation(Adjacencies.class).getAdjacency(),
+                Collections.emptyList());
         List<Adjacency> updatedAdjsList = new ArrayList<>();
         boolean isIpFromAnotherSubnet = false;
         for (Adjacency adj : vpnAdjsList) {
@@ -894,8 +925,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                           String.valueOf(adjString), wrtConfigTxn);
                 }
             } else {
-                if (port.getDeviceOwner()
-                    .equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF) && sn.getRouterId() != null) {
+                if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(port.getDeviceOwner())
+                        && sn.getRouterId() != null) {
                     Router rtr = neutronvpnUtils.getNeutronRouter(sn.getRouterId());
                     if (rtr != null && rtr.getRoutes() != null) {
                         List<Routes> extraRoutesToRemove = new ArrayList<>();
@@ -932,7 +963,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void deleteVpnInterface(String infName, @Nullable String vpnId,
-                                      TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
+                                      @Nullable TypedWriteTransaction<Configuration> wrtConfigTxn) {
         if (wrtConfigTxn == null) {
             ListenableFutures.addErrorLogging(
                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
@@ -978,7 +1009,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     protected void removeInternetVpnFromVpnInterface(Uuid vpnId, Port port,
-                                             TypedWriteTransaction<Datastore.Configuration> writeConfigTxn,
+                                             TypedWriteTransaction<Configuration> writeConfigTxn,
                                              Subnetmap sm) {
         if (vpnId == null || port == null) {
             return;
@@ -1023,8 +1054,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 mipToQuery, infName, vpnId.getValue());
                     }
                 }
-                List<FixedIps> ips = port.getFixedIps();
-                for (FixedIps ip : ips) {
+                for (FixedIps ip : requireNonNullElse(port.getFixedIps(), Collections.<FixedIps>emptyList())) {
                     String ipValue = ip.getIpAddress().stringValue();
                     //skip IPv4 address
                     if (!NeutronvpnUtils.getIpVersionFromString(ipValue).isIpVersionChosen(IpVersionChoice.IPV6)) {
@@ -1049,9 +1079,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected void updateVpnInterface(Uuid vpnId, Uuid oldVpnId, Port port, boolean isBeingAssociated,
+    protected void updateVpnInterface(Uuid vpnId, @Nullable Uuid oldVpnId, Port port, boolean isBeingAssociated,
                                       boolean isSubnetIp,
-                                      TypedWriteTransaction<Datastore.Configuration> writeConfigTxn) {
+                                      TypedWriteTransaction<Configuration> writeConfigTxn,
+                                      boolean isInternetVpn) {
         if (vpnId == null || port == null) {
             return;
         }
@@ -1105,13 +1136,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     Adjacencies adjacencies = new AdjacenciesBuilder().setAdjacency(adjacencyList).build();
                     vpnIfBuilder.addAugmentation(Adjacencies.class, adjacencies);
                 }
-                List<FixedIps> ips = port.getFixedIps();
-                for (FixedIps ip : ips) {
+                for (FixedIps ip : requireNonNullElse(port.getFixedIps(), Collections.<FixedIps>emptyList())) {
                     String ipValue = ip.getIpAddress().stringValue();
                     if (oldVpnId != null) {
                         neutronvpnUtils.removeVpnPortFixedIpToPort(oldVpnId.getValue(),
                                 ipValue, writeConfigTxn);
                     }
+                    if ((NeutronvpnUtils.getIpVersionFromString(ipValue) != IpVersionChoice.IPV6)
+                         && (isInternetVpn == true)) {
+                        continue;
+                    }
+
                     neutronvpnUtils.createVpnPortFixedIpToPort(vpnId.getValue(), ipValue, infName, port
                             .getMacAddress().getValue(), isSubnetIp, writeConfigTxn);
                 }
@@ -1128,8 +1163,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    public void createL3InternalVpn(Uuid vpn, String name, Uuid tenant, List<String> rd, List<String> irt,
-                                    List<String> ert, Uuid router, List<Uuid> networks) {
+    public void createL3InternalVpn(Uuid vpn, @Nullable String name, @Nullable Uuid tenant, @Nullable List<String> rd,
+            @Nullable List<String> irt, @Nullable List<String> ert, @Nullable Uuid router,
+            @Nullable List<Uuid> networks) {
 
         IpVersionChoice ipVersChoices = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(router);
 
@@ -1173,7 +1209,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * @throws Exception if association of L3VPN failed
      */
     public void createVpn(Uuid vpnId, String name, Uuid tenantId, List<String> rdList, List<String> irtList,
-                    List<String> ertList,  @Nullable List<Uuid> routerIdsList, List<Uuid> networkList,
+                    List<String> ertList,  @Nullable List<Uuid> routerIdsList, @Nullable List<Uuid> networkList,
                     VpnInstance.Type type, long l3vni) throws Exception {
 
         IpVersionChoice ipVersChoices = IpVersionChoice.UNDEFINED;
@@ -1381,7 +1417,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
                                 vpnsIdentifier);
                 if (optionalVpns.isPresent() && !optionalVpns.get().getVpnInstance().isEmpty()) {
-                    for (VpnInstance vpn : optionalVpns.get().getVpnInstance()) {
+                    for (VpnInstance vpn : requireNonNullElse(optionalVpns.get().getVpnInstance(),
+                            Collections.<VpnInstance>emptyList())) {
                         // eliminating implicitly created (router and VLAN provider external network specific) VPNs
                         // from getL3VPN output
                         if (vpn.getIpv4Family().getRouteDistinguisher() != null) {
@@ -1502,10 +1539,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
         int failurecount = 0;
         int warningcount = 0;
-        List<Uuid> vpns = input.getId();
+        List<Uuid> vpns = requireNonNullElse(input.getId(), Collections.emptyList());
         for (Uuid vpn : vpns) {
-            RpcError error;
-            String msg;
             try {
                 LOG.debug("L3VPN delete RPC: VpnID {}", vpn.getValue());
                 InstanceIdentifier<VpnInstance> vpnIdentifier =
@@ -1639,7 +1674,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected void removeSubnetFromVpn(final Uuid vpnId, Uuid subnet, Uuid internetVpnId) {
+    protected void removeSubnetFromVpn(final Uuid vpnId, Uuid subnet, @Nullable Uuid internetVpnId) {
         Preconditions.checkArgument(vpnId != null || internetVpnId != null,
                 "removeSubnetFromVpn: at least one VPN must be not null");
         LOG.debug("Removing subnet {} from vpn {}/{}", subnet.getValue(),
@@ -1734,7 +1769,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, wrtConfigTxn -> {
                 if (isBeingAssociated) {
                     updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(
-                            sm.getRouterInterfacePortId()), true, true, wrtConfigTxn);
+                            sm.getRouterInterfacePortId()), true, true, wrtConfigTxn, true);
                 } else {
                     removeInternetVpnFromVpnInterface(vpn,
                             neutronvpnUtils.getNeutronPort(sm.getRouterInterfacePortId()), wrtConfigTxn, sm);
@@ -1754,7 +1789,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         tx -> {
                             if (isBeingAssociated) {
                                 updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(port),
-                                        true, false, tx);
+                                        true, false, tx, true);
                             } else {
                                 removeInternetVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(port), tx, sm);
                             }
@@ -1763,6 +1798,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
+    @Nullable
     private Subnetmap updateVpnForSubnet(Uuid oldVpnId, Uuid newVpnId, Uuid subnet, boolean isBeingAssociated) {
         LOG.debug("Moving subnet {} from oldVpn {} to newVpn {} ", subnet.getValue(),
                 oldVpnId.getValue(), newVpnId.getValue());
@@ -1780,8 +1816,15 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
          * associated with internet BGP-VPN.
          */
         if (vpnExtUuid != null) {
-            //Update V6 Internet default route match with new VPN metadata
-            neutronvpnUtils.updateVpnInstanceWithFallback(vpnExtUuid, isBeingAssociated);
+            /* Update V6 Internet default route match with new VPN metadata.
+             * isBeingAssociated = true means oldVpnId is same as routerId
+             * isBeingAssociated = false means newVpnId is same as routerId
+            */
+            if (isBeingAssociated) {
+                neutronvpnUtils.updateVpnInstanceWithFallback(oldVpnId, vpnExtUuid, true);
+            } else {
+                neutronvpnUtils.updateVpnInstanceWithFallback(newVpnId, vpnExtUuid, true);
+            }
         }
         //Update Router Interface first synchronously.
         //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
@@ -1789,7 +1832,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
                     tx -> updateVpnInterface(newVpnId, oldVpnId,
                         neutronvpnUtils.getNeutronPort(sn.getRouterInterfacePortId()),
-                        isBeingAssociated, true, tx));
+                        isBeingAssociated, true, tx, false));
         Futures.addCallback(future, new FutureCallback<Void>() {
             @Override
             public void onSuccess(Void result) {
@@ -1804,7 +1847,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
                                     tx -> updateVpnInterface(newVpnId, oldVpnId,
                                             neutronvpnUtils.getNeutronPort(port), isBeingAssociated, false,
-                                            tx))));
+                                            tx, false))));
                     }
                 }
             }
@@ -1827,59 +1870,61 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     protected void addToNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
-        synchronized (routerId.getValue().intern()) {
-            InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
-            try {
-                Optional<RouterInterfaces> optRouterInterfaces =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                routerInterfacesId);
-                Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
+        final InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
+        final ReentrantLock lock = lockForUuid(routerId);
+        lock.lock();
+        try {
+            Optional<RouterInterfaces> optRouterInterfaces =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                        routerInterfacesId);
+            Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
                     .setInterfaceId(interfaceName).build();
-                if (optRouterInterfaces.isPresent()) {
-                    SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                            routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)),
-                            routerInterface);
-                } else {
-                    // TODO Shouldn't we be doing something with builder and interfaces?
-//                    RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
-//                    List<Interfaces> interfaces = new ArrayList<>();
-//                    interfaces.add(routerInterface);
+            if (optRouterInterfaces.isPresent()) {
+                SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                    routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)), routerInterface);
+            } else {
+                // TODO Shouldn't we be doing something with builder and interfaces?
+                //          RouterInterfacesBuilder builder = new RouterInterfacesBuilder().setRouterId(routerId);
+                //          List<Interfaces> interfaces = new ArrayList<>();
+                //          interfaces.add(routerInterface);
 
-                    SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                            routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)),
-                            routerInterface);
-                }
-            } catch (ReadFailedException | TransactionCommitFailedException e) {
-                LOG.error("Error reading router interfaces for {}", routerInterfacesId, e);
+                SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                    routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)), routerInterface);
             }
+        } catch (ReadFailedException | TransactionCommitFailedException e) {
+            LOG.error("Error reading router interfaces for {}", routerInterfacesId, e);
+        } finally {
+            lock.unlock();
         }
     }
 
     protected void removeFromNeutronRouterInterfacesMap(Uuid routerId, String interfaceName) {
-        synchronized (routerId.getValue().intern()) {
-            InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
-            try {
-                Optional<RouterInterfaces> optRouterInterfaces =
-                        SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                routerInterfacesId);
-                Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
+        final InstanceIdentifier<RouterInterfaces> routerInterfacesId = getRouterInterfacesId(routerId);
+        final ReentrantLock lock = lockForUuid(routerId);
+        lock.lock();
+        try {
+            Optional<RouterInterfaces> optRouterInterfaces =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                        routerInterfacesId);
+            Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
                     .setInterfaceId(interfaceName).build();
-                if (optRouterInterfaces.isPresent()) {
-                    RouterInterfaces routerInterfaces = optRouterInterfaces.get();
-                    List<Interfaces> interfaces = routerInterfaces.getInterfaces();
-                    if (interfaces != null && interfaces.remove(routerInterface)) {
-                        if (interfaces.isEmpty()) {
-                            SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                    routerInterfacesId);
-                        } else {
-                            SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                                    routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
-                        }
+            if (optRouterInterfaces.isPresent()) {
+                RouterInterfaces routerInterfaces = optRouterInterfaces.get();
+                List<Interfaces> interfaces = routerInterfaces.getInterfaces();
+                if (interfaces != null && interfaces.remove(routerInterface)) {
+                    if (interfaces.isEmpty()) {
+                        SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                            routerInterfacesId);
+                    } else {
+                        SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                            routerInterfacesId.child(Interfaces.class, new InterfacesKey(interfaceName)));
                     }
                 }
-            } catch (ReadFailedException | TransactionCommitFailedException e) {
-                LOG.error("Error reading the router interfaces for {}", routerInterfacesId, e);
             }
+        } catch (ReadFailedException | TransactionCommitFailedException e) {
+            LOG.error("Error reading the router interfaces for {}", routerInterfacesId, e);
+        } finally {
+            lock.unlock();
         }
     }
 
@@ -2238,18 +2283,18 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         // read VPNMaps
         VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
         List<RouterIds> routerIdsList = vpnMap != null ? vpnMap.getRouterIds() : null;
+        List<Uuid> routerUuidList = new ArrayList<>();
         // dissociate router
         if (routerIdsList != null && !routerIdsList.isEmpty()) {
-            for (RouterIds routerId : routerIdsList) {
-                dissociateRouterFromVpn(vpnId, routerId.getRouterId());
-            }
-            List<Uuid> rtrIdsList = routerIdsList.stream().map(routerId -> routerId.getRouterId())
-                    .collect(Collectors.toList());
-            if (rtrIdsList.contains(vpnId) && vpnMap.getNetworkIds() != null) {
-                // dissociate networks
-                dissociateNetworksFromVpn(vpnId, vpnMap.getNetworkIds());
+            for (RouterIds router : routerIdsList) {
+                Uuid routerId = router.getRouterId();
+                routerUuidList.add(routerId);
+                dissociateRouterFromVpn(vpnId, routerId);
             }
         }
+        if (!routerUuidList.contains(vpnId) && vpnMap.getNetworkIds() != null) {
+            dissociateNetworksFromVpn(vpnId, vpnMap.getNetworkIds());
+        }
         // remove entire vpnMaps node
         deleteVpnMapsNode(vpnId);
 
@@ -2266,29 +2311,22 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
         updateVpnMaps(vpnId, null, routerId, null, null);
-        LOG.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
-        IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+        LOG.debug("associateRouterToVpn: Updating association of subnets to external vpn {}", vpnId.getValue());
         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
+        IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
         for (Subnetmap sn : subMapList) {
-            updateVpnForSubnet(routerId, vpnId, sn.getId(), true);
             IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
             if (!ipVersion.isIpVersionChosen(ipVers)) {
                 ipVersion = ipVersion.addVersion(ipVers);
             }
         }
         if (ipVersion != IpVersionChoice.UNDEFINED) {
-            LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {} ", ipVersion,
-                    vpnId);
+            LOG.debug("associateRouterToVpn: Updating vpnInstanceOpDataEntrywith ip address family {} for VPN {} ",
+                    ipVersion, vpnId);
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
         }
-
-        try {
-            checkAndPublishRouterAssociatedtoVpnNotification(routerId, vpnId);
-            LOG.debug("notification upon association of router {} to VPN {} published", routerId.getValue(),
-                    vpnId.getValue());
-        } catch (Exception e) {
-            LOG.error("publishing of notification upon association of router {} to VPN {} failed : ", routerId
-                    .getValue(), vpnId.getValue(), e);
+        for (Subnetmap sn : subMapList) {
+            updateVpnForSubnet(routerId, vpnId, sn.getId(), true);
         }
     }
 
@@ -2311,31 +2349,24 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
 
+        clearFromVpnMaps(vpnId, routerId, null);
         List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
         for (Subnetmap sn : subMapList) {
-            IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
+            IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
             if (ipVersion.isIpVersionChosen(ipVers)) {
                 ipVersion = ipVersion.addVersion(ipVers);
             }
-            LOG.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
+            LOG.debug("dissociateRouterFromVpn: Updating association of subnets to internal vpn {}",
+                    routerId.getValue());
             updateVpnForSubnet(vpnId, routerId, sn.getId(), false);
         }
         if (ipVersion != IpVersionChoice.UNDEFINED) {
-            LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {} ",
+            LOG.debug("dissociateRouterFromVpn; Updating vpnInstanceOpDataEntry with ip address family {} for VPN {} ",
                     ipVersion, vpnId);
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion,
                     false);
         }
-        clearFromVpnMaps(vpnId, routerId, null);
-        try {
-            checkAndPublishRouterDisassociatedFromVpnNotification(routerId, vpnId);
-            LOG.debug("notification upon disassociation of router {} from VPN {} published", routerId.getValue(),
-                    vpnId.getValue());
-        } catch (Exception e) {
-            LOG.error("publishing of notification upon disassociation of router {} from VPN {} failed : ", routerId
-                    .getValue(), vpnId.getValue(), e);
-        }
     }
 
     /**
@@ -2349,6 +2380,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected List<String> associateNetworksToVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networkList) {
         List<String> failedNwList = new ArrayList<>();
         HashSet<Uuid> passedNwList = new HashSet<>();
+        boolean isExternalNetwork = false;
         if (networkList.isEmpty()) {
             LOG.error("associateNetworksToVpn: Failed as given networks list is empty, VPN Id: {}", vpnId.getValue());
             failedNwList.add(String.format("Failed to associate networks with VPN %s as given networks list is empty",
@@ -2402,6 +2434,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                             nw.getValue(), vpnId.getValue()));
                     continue;
                 }
+                if (NeutronvpnUtils.getIsExternal(network)) {
+                    isExternalNetwork = true;
+                }
                 List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
                 if (subnetmapList == null || subnetmapList.isEmpty()) {
                     passedNwList.add(nw);
@@ -2411,6 +2446,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     continue;
                 }
                 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+                for (Subnetmap subnetmap : subnetmapList) {
+                    IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
+                    if (!ipVersion.isIpVersionChosen(ipVers)) {
+                        ipVersion = ipVersion.addVersion(ipVers);
+                    }
+                }
+                if (ipVersion != IpVersionChoice.UNDEFINED) {
+                    LOG.debug("associateNetworksToVpn: Updating vpnInstanceOpDataEntry with ip address family {}"
+                            + " for VPN {} ", ipVersion, vpnId);
+                    neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
+                }
                 for (Subnetmap subnetmap : subnetmapList) {
                     Uuid subnetId = subnetmap.getId();
                     Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnetId);
@@ -2421,10 +2467,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 + " as it is already associated", subnetId.getValue(), vpnId.getValue()));
                         continue;
                     }
-                    IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
-                    if (!ipVersion.isIpVersionChosen(ipVers)) {
-                        ipVersion = ipVersion.addVersion(ipVers);
-                    }
                     if (!NeutronvpnUtils.getIsExternal(network)) {
                         LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnetId.getValue(),
                                 vpnId.getValue());
@@ -2434,11 +2476,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         passedNwList.add(nw);
                     }
                 }
-                if (ipVersion != IpVersionChoice.UNDEFINED) {
-                    LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {} ",
-                            ipVersion, vpnId);
-                    neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
-                }
                 passedNwList.add(nw);
             }
         } catch (ReadFailedException e) {
@@ -2447,7 +2484,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             failedNwList.add(String.format("Failed to associate VPN %s with networks %s: %s", vpnId.getValue(),
                     networkList, e));
         }
-        updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
+        //VpnMap update for ext-nw is already done in associateExtNetworkToVpn() method.
+        if (!isExternalNetwork) {
+            updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
+        }
         LOG.info("Network(s) {} associated to L3VPN {} successfully", passedNwList.toString(), vpnId.getValue());
         return failedNwList;
     }
@@ -2465,6 +2505,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             LOG.info("associateExtNetworkToVpn: set type {} for VPN {}", BgpvpnType.BGPVPNInternet, vpnId.getValue());
             neutronvpnUtils.updateVpnInstanceOpWithType(BgpvpnType.BGPVPNInternet, vpnId);
         }
+        //Update VpnMap with ext-nw is needed first before processing V6 internet default fallback flows
+        List<Uuid> extNwList = Collections.singletonList(extNet.key().getUuid());
+        updateVpnMaps(vpnId, null, null, null, extNwList);
         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
         for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
@@ -2472,7 +2515,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 LOG.error("associateExtNetworkToVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
                 continue;
             }
-            IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
+                continue;
+            }
             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
                 updateVpnInternetForSubnet(sm, vpnId, true);
             }
@@ -2480,10 +2526,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 ipVersion = ipVersion.addVersion(ipVers);
             }
         }
-        if (!ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
+        if (ipVersion != IpVersionChoice.UNDEFINED) {
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, true);
             LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
-            neutronvpnUtils.updateVpnInstanceWithFallback(vpnId, true);
+            neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, true);
         }
         return true;
     }
@@ -2536,7 +2582,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (NeutronvpnUtils.getIsExternal(network)) {
                 if (disassociateExtNetworkFromVpn(vpnId, network)) {
                     passedNwList.add(nw);
-                    continue;
                 } else {
                     LOG.error("dissociateNetworksFromVpn: Failed to withdraw Provider Network {} from VPN {}",
                               nw.getValue(), vpnId.getValue());
@@ -2545,30 +2590,32 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     continue;
                 }
             }
-            Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
             IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
             for (Uuid subnet : networkSubnets) {
                 Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
-                IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
+                IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
                 if (!ipVersion.isIpVersionChosen(ipVers)) {
                     ipVersion = ipVersion.addVersion(ipVers);
                 }
-                LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
-                          vpnId.getValue());
-                removeSubnetFromVpn(vpnId, subnet, null);
-                vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
-                        vpnId.getValue());
-                passedNwList.add(nw);
+                if (!NeutronvpnUtils.getIsExternal(network)) {
+                    LOG.debug("dissociateNetworksFromVpn: Withdraw subnet {} from VPN {}", subnet.getValue(),
+                            vpnId.getValue());
+                    removeSubnetFromVpn(vpnId, subnet, null);
+                    Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+                    vpnManager.removeRouteTargetsToSubnetAssociation(routeTargets, subnetmap.getSubnetIp(),
+                            vpnId.getValue());
+                    passedNwList.add(nw);
+                }
             }
             if (ipVersion != IpVersionChoice.UNDEFINED) {
-                LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
-                        ipVersion, vpnId);
+                LOG.debug("dissociateNetworksFromVpn: Updating vpnInstanceOpDataEntryupdate with ip address family {}"
+                        + " for VPN {}", ipVersion, vpnId);
                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
             }
         }
         clearFromVpnMaps(vpnId, null, new ArrayList<>(passedNwList));
-        LOG.info("Network(s) {} disassociated from L3VPN {} successfully", passedNwList.toString(),
-                vpnId.getValue());
+        LOG.info("dissociateNetworksFromVpn: Network(s) {} disassociated from L3VPN {} successfully",
+                passedNwList.toString(), vpnId.getValue());
         return failedNwList;
     }
 
@@ -2600,7 +2647,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 LOG.error("disassociateExtNetworkFromVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
                 continue;
             }
-            IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            IpVersionChoice ipVers = NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV4)) {
+                continue;
+            }
             if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
                 updateVpnInternetForSubnet(sm, vpnId, false);
             }
@@ -2608,11 +2658,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 ipVersion = ipVersion.addVersion(ipVers);
             }
         }
-        if (!ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
+        if (ipVersion != IpVersionChoice.UNDEFINED) {
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
             LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}",
                     vpnId.getValue());
-            neutronvpnUtils.updateVpnInstanceWithFallback(vpnId, false);
+            neutronvpnUtils.updateVpnInstanceWithFallback(/*routerId*/ null, vpnId, false);
         }
         return true;
     }
@@ -2728,8 +2778,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             List<String> fixedIPList = new ArrayList<>();
             Port port = neutronvpnUtils.getNeutronPort(portId);
             if (port != null) {
-                List<FixedIps> fixedIPs = port.getFixedIps();
-                for (FixedIps ip : fixedIPs) {
+                for (FixedIps ip : requireNonNullElse(port.getFixedIps(), Collections.<FixedIps>emptyList())) {
                     fixedIPList.add(ip.getIpAddress().stringValue());
                 }
             } else {
@@ -2892,6 +2941,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return neutronvpnUtils.getNeutronSubnet(subnetId);
     }
 
+    @Nullable
     protected IpAddress getNeutronSubnetGateway(Uuid subnetId) {
         Subnet sn = neutronvpnUtils.getNeutronSubnet(subnetId);
         if (null != sn) {
@@ -2936,7 +2986,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
         Optional<Ports> ports = syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
         if (ports.isPresent() && ports.get().getPort() != null) {
-            for (Port port : ports.get().getPort()) {
+            for (Port port : requireNonNullElse(ports.get().getPort(), Collections.<Port>emptyList())) {
                 List<FixedIps> fixedIPs = port.getFixedIps();
                 if (fixedIPs != null && !fixedIPs.isEmpty()) {
                     List<String> ipList = new ArrayList<>();
@@ -2990,9 +3040,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             result.add("");
             result.add("------------------------------------------------------------------------------------");
             result.add("");
-            List<L3vpnInstances> vpnList = rpcResult.getResult().getL3vpnInstances();
-            for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
-                    .rev150602.VpnInstance vpn : vpnList) {
+            for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnInstance vpn :
+                    requireNonNullElse(rpcResult.getResult().getL3vpnInstances(),
+                        Collections.<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602
+                            .VpnInstance>emptyList())) {
                 String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
                         : "\"                 " + "                  \"";
                 result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
@@ -3070,15 +3121,16 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     private void createExternalVpnInterface(Uuid vpnId, String infName,
-                                            TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
+                                            TypedWriteTransaction<Configuration> wrtConfigTxn) {
         writeVpnInterfaceToDs(Collections.singletonList(vpnId), infName, null, vpnId /* external network id */,
                 false /* not a router iface */, wrtConfigTxn);
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void writeVpnInterfaceToDs(@Nonnull Collection<Uuid> vpnIdList, String infName, Adjacencies adjacencies,
-            Uuid networkUuid, Boolean isRouterInterface, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
+    private void writeVpnInterfaceToDs(@Nonnull Collection<Uuid> vpnIdList, String infName,
+            @Nullable Adjacencies adjacencies, Uuid networkUuid, Boolean isRouterInterface,
+            TypedWriteTransaction<Configuration> wrtConfigTxn) {
         if (vpnIdList.isEmpty() || infName == null) {
             LOG.error("vpnid is empty or interface({}) is null", infName);
             return;
@@ -3105,7 +3157,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         if (networkUuid != null) {
             Network portNetwork = neutronvpnUtils.getNeutronNetwork(networkUuid);
             ProviderTypes providerType = NeutronvpnUtils.getProviderNetworkType(portNetwork);
-            NetworkAttributes.NetworkType networkType = (providerType != null)
+            NetworkAttributes.NetworkType networkType = providerType != null
                     ? NetworkAttributes.NetworkType.valueOf(providerType.getName()) : null;
             String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(portNetwork);
             vpnb.setNetworkId(networkUuid).setNetworkType(networkType)
@@ -3125,7 +3177,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     private void updateVpnInterfaceWithAdjacencies(Uuid vpnId, String infName, Adjacencies adjacencies,
-                                                   TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
+                                                   TypedWriteTransaction<Configuration> wrtConfigTxn) {
         if (vpnId == null || infName == null) {
             LOG.error("vpn id or interface is null");
             return;
@@ -3191,22 +3243,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return help.toString();
     }
 
-    private void checkAndPublishRouterAssociatedtoVpnNotification(Uuid routerId, Uuid vpnId) throws
-            InterruptedException {
-        RouterAssociatedToVpn routerAssociatedToVpn = new RouterAssociatedToVpnBuilder().setRouterId(routerId)
-                .setVpnId(vpnId).build();
-        LOG.info("publishing notification upon association of router to VPN");
-        notificationPublishService.putNotification(routerAssociatedToVpn);
-    }
-
-    private void checkAndPublishRouterDisassociatedFromVpnNotification(Uuid routerId, Uuid vpnId) throws
-            InterruptedException {
-        RouterDisassociatedFromVpn routerDisassociatedFromVpn =
-            new RouterDisassociatedFromVpnBuilder().setRouterId(routerId).setVpnId(vpnId).build();
-        LOG.info("publishing notification upon disassociation of router from VPN");
-        notificationPublishService.putNotification(routerDisassociatedFromVpn);
-    }
-
     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
     }
@@ -3307,19 +3343,19 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return existingVpnName;
     }
 
-    private String formatAndLog(Consumer<String> logger, String template, Object arg) {
+    private static String formatAndLog(Consumer<String> logger, String template, Object arg) {
         return logAndReturnMessage(logger, MessageFormatter.format(template, arg));
     }
 
-    private String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
+    private static String formatAndLog(Consumer<String> logger, String template, Object arg1, Object arg2) {
         return logAndReturnMessage(logger, MessageFormatter.format(template, arg1, arg2));
     }
 
-    private String formatAndLog(Consumer<String> logger, String template, Object... args) {
+    private static String formatAndLog(Consumer<String> logger, String template, Object... args) {
         return logAndReturnMessage(logger, MessageFormatter.arrayFormat(template, args));
     }
 
-    private String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
+    private static String logAndReturnMessage(Consumer<String> logger, FormattingTuple tuple) {
         String message = tuple.getMessage();
         logger.accept(message);
         return message;
@@ -3328,24 +3364,32 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected void addV6PrivateSubnetToExtNetwork(@Nonnull Uuid routerId, @Nonnull Uuid internetVpnId,
                                                   @Nonnull Subnetmap subnetMap) {
         updateVpnInternetForSubnet(subnetMap, internetVpnId, true);
-        if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
-                IpVersionChoice.IPV6, routerId, true)) {
+        neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
+        if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(IpVersionChoice.IPV6, routerId, true)) {
             neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, true);
             LOG.info("addV6PrivateSubnetToExtNetwork: Advertise IPv6 Private Subnet {} to Internet VPN {}",
-                    subnetMap.getId(), internetVpnId.getValue());
+                    subnetMap.getId().getValue(), internetVpnId.getValue());
         }
-        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, true);
     }
 
     protected void removeV6PrivateSubnetToExtNetwork(@Nonnull Uuid routerId, @Nonnull Uuid internetVpnId,
                                                      @Nonnull Subnetmap subnetMap) {
         updateVpnInternetForSubnet(subnetMap, internetVpnId, false);
-        if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
-                IpVersionChoice.IPV6, routerId, false)) {
-            neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, false);
-            LOG.info("removeV6PrivateSubnetToExtNetwork: withdraw IPv6 Private subnet {} from Internet VPN {}",
-                    subnetMap.getId(), internetVpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, false);
+    }
+
+    protected void programV6InternetFallbackFlow(Uuid routerId, Uuid internetVpnId, int addOrRemove) {
+        if (neutronvpnUtils.isV6SubnetPartOfRouter(routerId)) {
+            LOG.debug("processV6InternetFlowsForRtr: Successfully {} V6 internet vpn {} default fallback rule "
+                            + "for the router {}", addOrRemove == NwConstants.ADD_FLOW ? "added" : "removed",
+                    internetVpnId.getValue(), routerId.getValue());
+            neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, addOrRemove == NwConstants.ADD_FLOW
+                    ? true : false);
         }
-        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, false);
+    }
+
+    private static ReentrantLock lockForUuid(Uuid uuid) {
+        // FIXME: prove that this locks only on Uuids and not some other entity or create a separate lock domain
+        return JvmGlobalLocks.getLockForString(uuid.getValue());
     }
 }