IPv6 FIB enteries not appearing if ExtNwt enabled
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronvpnManager.java
index 7986020796dbb99e683768f8b10bcf2869ac0ac8..89abac66d910ee748b0c2a1e98cf8774f01eb1f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2015, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright © 2015, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -8,9 +8,8 @@
 package org.opendaylight.netvirt.neutronvpn;
 
 import static java.util.Collections.singletonList;
-import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
-import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
 import static org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker.syncReadOptional;
+import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
@@ -20,7 +19,6 @@ import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -38,6 +36,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.annotation.PreDestroy;
@@ -45,13 +44,14 @@ import javax.inject.Inject;
 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.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.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
+import org.opendaylight.genius.infra.Datastore;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
+import org.opendaylight.genius.infra.TypedWriteTransaction;
 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.KeyedLocks;
 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
@@ -93,6 +93,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.lea
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry.BgpvpnType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
@@ -101,6 +102,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateRouterOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateEVPNOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNInput;
@@ -115,6 +118,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateNetworksOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DissociateRouterOutputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetEVPNOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortInput;
@@ -147,6 +152,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMapKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.vpnmap.RouterIds;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.vpnmap.RouterIdsBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.AddStaticRouteOutput;
@@ -195,6 +202,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     private final NeutronEvpnUtils neutronEvpnUtils;
     private final JobCoordinator jobCoordinator;
     private final NeutronvpnUtils neutronvpnUtils;
+    private final IVpnManager vpnManager;
     private final ConcurrentHashMap<Uuid, Uuid> unprocessedPortsMap = new ConcurrentHashMap<>();
     private final NeutronvpnAlarms neutronvpnAlarm = new NeutronvpnAlarms();
     private final KeyedLocks<Uuid> vpnLock = new KeyedLocks<>();
@@ -218,6 +226,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         neutronEvpnUtils = new NeutronEvpnUtils(dataBroker, vpnManager, jobCoordinator);
         this.jobCoordinator = jobCoordinator;
         this.neutronvpnUtils = neutronvpnUtils;
+        this.vpnManager = vpnManager;
 
         configureFeatures();
     }
@@ -232,7 +241,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         InstanceIdentifier<Feature> iid = InstanceIdentifier.builder(
                         Neutron.class).child(Features.class).child(
                         Feature.class, new FeatureKey(OperationalPortStatus.class)).build();
-        Feature feature = new FeatureBuilder().setKey(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) {
@@ -259,7 +268,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         subnetId.getValue());
                     return;
                 }
-                SubnetmapBuilder subnetmapBuilder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId))
+                SubnetmapBuilder subnetmapBuilder = new SubnetmapBuilder().withKey(new SubnetmapKey(subnetId))
                         .setId(subnetId).setSubnetIp(subnetIp).setTenantId(tenantId).setNetworkId(networkId)
                         .setNetworkType(networkType).setSegmentationId(segmentationId);
                 LOG.debug("createSubnetmapNode: Adding a new subnet node in Subnetmaps DS for subnet {}",
@@ -488,7 +497,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void deleteSubnetMapNode(Uuid subnetId) {
         InstanceIdentifier<Subnetmap> subnetMapIdentifier =
-                InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,new SubnetmapKey(subnetId)).build();
+                InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
         LOG.debug("removing subnetMap node: {} ", subnetId.getValue());
         try {
             synchronized (subnetId.getValue().intern()) {
@@ -546,7 +555,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 builder = new VpnInstanceBuilder(optionalVpn.get());
                 LOG.debug("updating existing vpninstance node");
             } else {
-                builder = new VpnInstanceBuilder().setKey(new VpnInstanceKey(vpnName)).setVpnInstanceName(vpnName)
+                builder = new VpnInstanceBuilder().withKey(new VpnInstanceKey(vpnName)).setVpnInstanceName(vpnName)
                         .setType(type).setL3vni(l3vni);
             }
             if (irt != null && !irt.isEmpty()) {
@@ -558,14 +567,14 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         irt.remove(common);
                         ert.remove(common);
                         VpnTarget vpnTarget =
-                                new VpnTargetBuilder().setKey(new VpnTargetKey(common)).setVrfRTValue(common)
+                                new VpnTargetBuilder().withKey(new VpnTargetKey(common)).setVrfRTValue(common)
                                         .setVrfRTType(VpnTarget.VrfRTType.Both).build();
                         vpnTargetList.add(vpnTarget);
                     }
                 }
                 for (String importRT : irt) {
                     VpnTarget vpnTarget =
-                            new VpnTargetBuilder().setKey(new VpnTargetKey(importRT)).setVrfRTValue(importRT)
+                            new VpnTargetBuilder().withKey(new VpnTargetKey(importRT)).setVrfRTValue(importRT)
                                     .setVrfRTType(VpnTarget.VrfRTType.ImportExtcommunity).build();
                     vpnTargetList.add(vpnTarget);
                 }
@@ -574,7 +583,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (ert != null && !ert.isEmpty()) {
                 for (String exportRT : ert) {
                     VpnTarget vpnTarget =
-                            new VpnTargetBuilder().setKey(new VpnTargetKey(exportRT)).setVrfRTValue(exportRT)
+                            new VpnTargetBuilder().withKey(new VpnTargetKey(exportRT)).setVrfRTValue(exportRT)
                                     .setVrfRTType(VpnTarget.VrfRTType.ExportExtcommunity).build();
                     vpnTargetList.add(vpnTarget);
                 }
@@ -631,7 +640,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    private void updateVpnMaps(Uuid vpnId, String name, Uuid router, Uuid tenantId, List<Uuid> networks) {
+    protected void updateVpnMaps(Uuid vpnId, String name, Uuid router, Uuid tenantId, List<Uuid> networks) {
         VpnMapBuilder builder;
         boolean isLockAcquired = false;
         InstanceIdentifier<VpnMap> vpnMapIdentifier = InstanceIdentifier.builder(VpnMaps.class)
@@ -644,7 +653,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (optionalVpnMap.isPresent()) {
                 builder = new VpnMapBuilder(optionalVpnMap.get());
             } else {
-                builder = new VpnMapBuilder().setKey(new VpnMapKey(vpnId)).setVpnId(vpnId);
+                builder = new VpnMapBuilder().withKey(new VpnMapKey(vpnId)).setVpnId(vpnId);
             }
 
             if (name != null) {
@@ -654,7 +663,14 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 builder.setTenantId(tenantId);
             }
             if (router != null) {
-                builder.setRouterId(router);
+                RouterIds vpnRouterId = new RouterIdsBuilder().setRouterId(router).build();
+                List<RouterIds> rtrIds = builder.getRouterIds();
+                if (rtrIds == null) {
+                    rtrIds = Collections.singletonList(vpnRouterId);
+                } else {
+                    rtrIds.add(vpnRouterId);
+                }
+                builder.setRouterIds(rtrIds);
             }
             if (networks != null) {
                 List<Uuid> nwList = builder.getNetworkIds();
@@ -696,8 +712,14 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         if (optionalVpnMap.isPresent()) {
             VpnMap vpnMap = optionalVpnMap.get();
             VpnMapBuilder vpnMapBuilder = new VpnMapBuilder(vpnMap);
+            List<RouterIds> rtrIds = vpnMap.getRouterIds();
+            if (rtrIds == null) {
+                rtrIds = new ArrayList<>();
+            }
             if (routerId != null) {
                 if (vpnMap.getNetworkIds() == null && routerId.equals(vpnMap.getVpnId())) {
+                    rtrIds.add(new RouterIdsBuilder().setRouterId(routerId).build());
+                    vpnMapBuilder.setRouterIds(rtrIds);
                     try {
                         // remove entire node in case of internal VPN
                         isLockAcquired = vpnLock.tryLock(vpnId, LOCK_WAIT_TIME, TimeUnit.SECONDS);
@@ -712,8 +734,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         }
                     }
                     return;
+                } else if (vpnMap.getNetworkIds() == null && !routerId.equals(vpnMap.getVpnId())) {
+                    rtrIds.remove(new RouterIdsBuilder().setRouterId(routerId).build());
+                    vpnMapBuilder.setRouterIds(rtrIds);
+                    LOG.debug("Removing routerId {} in vpnMaps for the vpn {}", routerId, vpnId.getValue());
                 }
-                vpnMapBuilder.setRouterId(null);
             }
             if (networkIds != null) {
                 List<Uuid> vpnNw = vpnMap.getNetworkIds();
@@ -764,15 +789,16 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     protected Adjacencies createPortIpAdjacencies(Port port, Boolean isRouterInterface,
-                                  WriteTransaction wrtConfigTxn, Subnetmap sn, VpnInterface vpnIface) {
+                                                  TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn,
+                                                  Subnetmap sn, VpnInterface vpnIface) {
         List<Adjacency> adjList = new ArrayList<>();
         if (vpnIface != null) {
-            adjList = vpnIface.getAugmentation(Adjacencies.class).getAdjacency();
+            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()) {
-            String ipValue = String.valueOf(ip.getIpAddress().getValue());
+            String ipValue = ip.getIpAddress().stringValue();
             String ipPrefix = ip.getIpAddress().getIpv4Address() != null ? ipValue + "/32" : ipValue + "/128";
             if (sn != null && !FibHelper.doesPrefixBelongToSubnet(ipPrefix, sn.getSubnetIp(), false)) {
                 continue;
@@ -783,7 +809,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 neutronvpnUtils.createVpnPortFixedIpToPort(vpnId.getValue(), ipValue,
                         infName, port.getMacAddress().getValue(), isRouterInterface, wrtConfigTxn);
                 //Create Neutron port adjacency if VPN presence is existing for subnet
-                Adjacency vmAdj = new AdjacencyBuilder().setKey(new AdjacencyKey(ipPrefix)).setIpAddress(ipPrefix)
+                Adjacency vmAdj = new AdjacencyBuilder().withKey(new AdjacencyKey(ipPrefix)).setIpAddress(ipPrefix)
                         .setMacAddress(port.getMacAddress().getValue()).setAdjacencyType(AdjacencyType.PrimaryAdjacency)
                         .setSubnetId(ip.getSubnetId()).build();
                 if (!adjList.contains(vmAdj)) {
@@ -792,7 +818,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             }
             Uuid routerId = snTemp != null ? snTemp.getRouterId() : null;
             if (snTemp != null && snTemp.getInternetVpnId() != null) {
-                neutronvpnUtils.createVpnPortFixedIpToPort(sn.getInternetVpnId().getValue(),
+                neutronvpnUtils.createVpnPortFixedIpToPort(snTemp.getInternetVpnId().getValue(),
                     ipValue, infName, port.getMacAddress().getValue(), isRouterInterface, wrtConfigTxn);
             }
             if (routerId != null) {
@@ -812,28 +838,29 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return new AdjacenciesBuilder().setAdjacency(adjList).build();
     }
 
-    protected void createVpnInterface(Collection<Uuid> vpnIds, Port port, WriteTransaction wrtConfigTxn) {
+    protected void createVpnInterface(Collection<Uuid> vpnIds, Port port,
+                                      TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
         boolean isRouterInterface = false;
         if (port.getDeviceOwner() != null) {
-            isRouterInterface = port.getDeviceOwner().equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF);
+            isRouterInterface = NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(port.getDeviceOwner());
         }
         Adjacencies adjs = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn, null, null);
         String infName = port.getUuid().getValue();
         LOG.trace("createVpnInterface for Port: {}, isRouterInterface: {}", infName, isRouterInterface);
-        writeVpnInterfaceToDs(vpnIds, infName, adjs, isRouterInterface, wrtConfigTxn);
+        writeVpnInterfaceToDs(vpnIds, infName, adjs, port.getNetworkId(), isRouterInterface, wrtConfigTxn);
     }
 
     protected void withdrawPortIpFromVpnIface(Uuid vpnId, Uuid internetVpnId,
-                       Port port, Subnetmap sn, WriteTransaction wrtConfigTxn) {
+                       Port port, Subnetmap sn, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
         String infName = port.getUuid().getValue();
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
         Optional<VpnInterface> optionalVpnInterface = null;
         LOG.debug("withdrawPortIpFromVpnIface vpn {} internetVpn {} Port {}",
-                   vpnId, internetVpnId, infName);
+                  vpnId, internetVpnId, infName);
         try {
             optionalVpnInterface = SingleTransactionDataBroker
-                .syncReadOptional(dataBroker, LogicalDatastoreType
-                .CONFIGURATION, vpnIfIdentifier);
+                    .syncReadOptional(dataBroker, LogicalDatastoreType
+                    .CONFIGURATION, vpnIfIdentifier);
         } catch (ReadFailedException e) {
             LOG.error("withdrawPortIpFromVpnIface: Error reading the VPN interface for {}", vpnIfIdentifier, e);
             return;
@@ -843,7 +870,7 @@ 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().getAugmentation(Adjacencies.class).getAdjacency();
+        List<Adjacency> vpnAdjsList = optionalVpnInterface.get().augmentation(Adjacencies.class).getAdjacency();
         List<Adjacency> updatedAdjsList = new ArrayList<>();
         boolean isIpFromAnotherSubnet = false;
         for (Adjacency adj : vpnAdjsList) {
@@ -860,15 +887,15 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                       adjString, vpnId);
                 if (vpnId != null) {
                     neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(),
-                          String.valueOf(adjString), wrtConfigTxn);
+                            String.valueOf(adjString), wrtConfigTxn);
                 }
                 if (internetVpnId != null) {
                     neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
-                            String.valueOf(adjString), wrtConfigTxn);
+                          String.valueOf(adjString), wrtConfigTxn);
                 }
             } else {
                 if (port.getDeviceOwner()
-                    .equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF) && sn.getRouterId() != null)  {
+                    .equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF) && sn.getRouterId() != null) {
                     Router rtr = neutronvpnUtils.getNeutronRouter(sn.getRouterId());
                     if (rtr != null && rtr.getRoutes() != null) {
                         List<Routes> extraRoutesToRemove = new ArrayList<>();
@@ -891,9 +918,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         if (vpnId != null) {
             updateVpnInterfaceWithAdjacencies(vpnId, infName, adjacencies, wrtConfigTxn);
         }
-        if (internetVpnId != null) {
-            updateVpnInterfaceWithAdjacencies(internetVpnId, infName, adjacencies, wrtConfigTxn);
-        }
         if (!isIpFromAnotherSubnet) {
             // no more subnetworks for neutron port
             if (sn != null && sn.getRouterId() != null) {
@@ -907,10 +931,12 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void deleteVpnInterface(String infName, @Nullable String vpnId, WriteTransaction wrtConfigTxn) {
+    protected void deleteVpnInterface(String infName, @Nullable String vpnId,
+                                      TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
         if (wrtConfigTxn == null) {
             ListenableFutures.addErrorLogging(
-                    txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> deleteVpnInterface(infName, vpnId, tx)),
+                    txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                        tx -> deleteVpnInterface(infName, vpnId, tx)),
                     LOG, "Error deleting VPN interface {} {}", infName, vpnId);
             return;
         }
@@ -943,16 +969,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
                         .setVpnInstanceNames(vpnList);
-                wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIfBuilder
+                wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder
                         .build());
             }
         }
         LOG.debug("Deleting vpn interface {}", infName);
-        wrtConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
+        wrtConfigTxn.delete(vpnIfIdentifier);
     }
 
     protected void removeVpnFromVpnInterface(Uuid vpnId, Port port,
-                                     WriteTransaction writeConfigTxn, Subnetmap sm) {
+                                             TypedWriteTransaction<Datastore.Configuration> writeConfigTxn,
+                                             Subnetmap sm) {
         if (vpnId == null || port == null) {
             return;
         }
@@ -970,7 +997,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
                          .setVpnInstanceNames(listVpn);
-                Adjacencies adjs = vpnIfBuilder.getAugmentation(Adjacencies.class);
+                Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
                 LOG.debug("Updating vpn interface {}", infName);
                 List<Adjacency> adjacencyList = adjs != null ? adjs.getAdjacency() : new ArrayList<>();
                 Iterator<Adjacency> adjacencyIter = adjacencyList.iterator();
@@ -998,7 +1025,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
                 List<FixedIps> ips = port.getFixedIps();
                 for (FixedIps ip : ips) {
-                    String ipValue = String.valueOf(ip.getIpAddress().getValue());
+                    String ipValue = ip.getIpAddress().stringValue();
+                    //skip IPv4 address
+                    if (!NeutronvpnUtils.getIpVersionFromString(ipValue).isIpVersionChosen(IpVersionChoice.IPV6)) {
+                        continue;
+                    }
                     neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(),
                             ipValue, writeConfigTxn);
                 }
@@ -1008,8 +1039,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     }
                     deleteVpnInterface(port.getUuid().getValue(), null /* vpn-id */, writeConfigTxn);
                 } else {
-                    writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIfBuilder
-                            .build());
+                    writeConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
                 }
             } else {
                 LOG.info("removeVpnFromVpnInterface: VPN Interface {} not found", infName);
@@ -1020,7 +1050,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     protected void updateVpnInterface(Uuid vpnId, Uuid oldVpnId, Port port, boolean isBeingAssociated,
-                                      boolean isSubnetIp, WriteTransaction writeConfigTxn) {
+                                      boolean isSubnetIp,
+                                      TypedWriteTransaction<Datastore.Configuration> writeConfigTxn) {
         if (vpnId == null || port == null) {
             return;
         }
@@ -1047,10 +1078,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     listVpn.add(vpnInstance);
                 }
                 VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get())
-                         .setVpnInstanceNames(listVpn);
+                        .setVpnInstanceNames(listVpn);
                 LOG.debug("Updating vpn interface {}", infName);
                 if (!isBeingAssociated) {
-                    Adjacencies adjs = vpnIfBuilder.getAugmentation(Adjacencies.class);
+                    Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
                     List<Adjacency> adjacencyList = adjs != null ? adjs.getAdjacency() : new ArrayList<>();
                     Iterator<Adjacency> adjacencyIter = adjacencyList.iterator();
                     while (adjacencyIter.hasNext()) {
@@ -1076,7 +1107,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
                 List<FixedIps> ips = port.getFixedIps();
                 for (FixedIps ip : ips) {
-                    String ipValue = String.valueOf(ip.getIpAddress().getValue());
+                    String ipValue = ip.getIpAddress().stringValue();
                     if (oldVpnId != null) {
                         neutronvpnUtils.removeVpnPortFixedIpToPort(oldVpnId.getValue(),
                                 ipValue, writeConfigTxn);
@@ -1084,8 +1115,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     neutronvpnUtils.createVpnPortFixedIpToPort(vpnId.getValue(), ipValue, infName, port
                             .getMacAddress().getValue(), isSubnetIp, writeConfigTxn);
                 }
-                writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIfBuilder
-                        .build());
+                writeConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
             } else {
                 LOG.error("VPN Interface {} not found", infName);
             }
@@ -1130,43 +1160,50 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * Performs the creation of a Neutron L3VPN, associating the new VPN to the
      * specified Neutron Networks and Routers.
      *
-     * @param vpn Uuid of the VPN tp be created
+     * @param vpnId Uuid of the VPN tp be created
      * @param name Representative name of the new VPN
-     * @param tenant Uuid of the Tenant under which the VPN is going to be created
-     * @param rd Route-distinguisher for the VPN
-     * @param irt A list of Import Route Targets
-     * @param ert A list of Export Route Targets
-     * @param router neutron router Id to associate with created VPN
-     * @param networks UUID of the neutron network the VPN may be associated to
+     * @param tenantId Uuid of the Tenant under which the VPN is going to be created
+     * @param rdList Route-distinguisher for the VPN
+     * @param irtList A list of Import Route Targets
+     * @param ertList A list of Export Route Targets
+     * @param routerIdsList ist of neutron router Id to associate with created VPN
+     * @param networkList UUID of the neutron network the VPN may be associated to
      * @param type Type of the VPN Instance
      * @param l3vni L3VNI for the VPN Instance using VxLAN as the underlay
      * @throws Exception if association of L3VPN failed
      */
-    public void createVpn(Uuid vpn, String name, Uuid tenant, List<String> rd, List<String> irt, List<String> ert,
-                            Uuid router, List<Uuid> networks, VpnInstance.Type type, long l3vni)
-                                    throws Exception {
+    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,
+                    VpnInstance.Type type, long l3vni) throws Exception {
 
         IpVersionChoice ipVersChoices = IpVersionChoice.UNDEFINED;
 
-        if (router != null) {
-            IpVersionChoice vers = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(router);
-            ipVersChoices = ipVersChoices.addVersion(vers);
+        if (routerIdsList != null && !routerIdsList.isEmpty()) {
+            for (Uuid routerId : routerIdsList) {
+                IpVersionChoice vers = neutronvpnUtils.getIpVersionChoicesFromRouterUuid(routerId);
+                ipVersChoices = ipVersChoices.addVersion(vers);
+            }
         }
-        updateVpnInstanceNode(vpn, rd, irt, ert, type, l3vni, ipVersChoices);
+        updateVpnInstanceNode(vpnId, rdList, irtList, ertList, type, l3vni, ipVersChoices);
 
         // Please note that router and networks will be filled into VPNMaps
         // by subsequent calls here to associateRouterToVpn and
         // associateNetworksToVpn
-        updateVpnMaps(vpn, name, null, tenant, null);
+        updateVpnMaps(vpnId, name, null, tenantId, null);
+        LOG.debug("Created L3VPN with ID {}, name {}, tenantID {}, RDList {}, iRTList {}, eRTList{}, routerIdsList {}, "
+                        + "networkList {}", vpnId.getValue(), name, tenantId, rdList, irtList, ertList, routerIdsList,
+                networkList);
 
-        if (router != null) {
-            associateRouterToVpn(vpn, router);
+        if (routerIdsList != null && !routerIdsList.isEmpty()) {
+            for (Uuid routerId : routerIdsList) {
+                associateRouterToVpn(vpnId, routerId);
+            }
         }
-        if (networks != null) {
-            List<String> failStrings = associateNetworksToVpn(vpn, networks);
+        if (networkList != null) {
+            List<String> failStrings = associateNetworksToVpn(vpnId, networkList);
             if (!failStrings.isEmpty()) {
                 LOG.error("VPN {} association to networks failed for networks: {}. ",
-                        vpn.getValue(), failStrings.toString());
+                        vpnId.getValue(), failStrings.toString());
                 throw new Exception(failStrings.toString());
             }
         }
@@ -1178,7 +1215,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public Future<RpcResult<CreateL3VPNOutput>> createL3VPN(CreateL3VPNInput input) {
+    public ListenableFuture<RpcResult<CreateL3VPNOutput>> createL3VPN(CreateL3VPNInput input) {
 
         CreateL3VPNOutputBuilder opBuilder = new CreateL3VPNOutputBuilder();
         SettableFuture<RpcResult<CreateL3VPNOutput>> result = SettableFuture.create();
@@ -1187,6 +1224,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         int warningcount = 0;
 
         List<L3vpn> vpns = input.getL3vpn();
+        if (vpns == null) {
+            vpns = Collections.emptyList();
+        }
         for (L3vpn vpn : vpns) {
             if (neutronvpnUtils.doesVpnExist(vpn.getId())) {
                 errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
@@ -1231,23 +1271,27 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 warningcount++;
                 continue;
             }
-            if (vpn.getRouterId() != null) {
-                if (neutronvpnUtils.getNeutronRouter(vpn.getRouterId()) == null) {
-                    errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
-                            formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to router not found {}",
-                                    vpn.getId().getValue(), vpn.getRouterId().getValue())));
-                    warningcount++;
-                    continue;
-                }
-                Uuid vpnId = neutronvpnUtils.getVpnForRouter(vpn.getRouterId(), true);
-                if (vpnId != null) {
-                    errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
-                            formatAndLog(LOG::warn,
-                                    "Creation of L3VPN failed for VPN {} due to router {} already associated to "
-                                            + "another VPN {}", vpn.getId().getValue(), vpn.getRouterId().getValue(),
-                                    vpnId.getValue())));
-                    warningcount++;
-                    continue;
+            if (vpn.getRouterIds() != null && !vpn.getRouterIds().isEmpty()) {
+                List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds>
+                        routerIdsList = vpn.getRouterIds();
+                for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds
+                        routerId : routerIdsList) {
+                    if (neutronvpnUtils.getNeutronRouter(routerId.getRouterId()) == null) {
+                        errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
+                                formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to absense of routers"
+                                        + "{}", vpn.getId(), routerId.getRouterId())));
+                        warningcount++;
+                        continue;
+                    }
+                    Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
+                    if (vpnId != null) {
+                        errorList.add(RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input",
+                                formatAndLog(LOG::warn, "Creation of L3VPN failed for VPN {} due to router {} already "
+                                                + "associated to another VPN {}", vpn.getId(), routerId.getRouterId(),
+                                        vpnId.getValue())));
+                        warningcount++;
+                        continue;
+                    }
                 }
             }
             if (vpn.getNetworkIds() != null) {
@@ -1274,9 +1318,20 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     continue;
                 }
             }
+            List<Uuid> rtrIdsList = new ArrayList<>();
+            if (vpn.getRouterIds() != null && !vpn.getRouterIds().isEmpty()) {
+                for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpn.instance.RouterIds
+                        rtrId : vpn.getRouterIds()) {
+                    rtrIdsList.add(rtrId.getRouterId());
+                }
+            }
             try {
+                LOG.debug("L3VPN add RPC: VpnID {}, name {}, tenantID {}, RDList {}, iRTList {}, eRTList{}, "
+                                + "routerIdList {}, networksList {}", vpn.getId().getValue(), vpn.getName(),
+                        vpn.getTenantId(), vpn.getRouteDistinguisher().toString(), vpn.getImportRT().toString(),
+                        vpn.getExportRT().toString(), rtrIdsList, vpn.getNetworkIds());
                 createVpn(vpn.getId(), vpn.getName(), vpn.getTenantId(), vpn.getRouteDistinguisher(),
-                        vpn.getImportRT(), vpn.getExportRT(), vpn.getRouterId(), vpn.getNetworkIds(),
+                        vpn.getImportRT(), vpn.getExportRT(), rtrIdsList, vpn.getNetworkIds(),
                         vpnInstanceType, l3vni);
             } catch (Exception ex) {
                 errorList.add(RpcResultBuilder.newError(ErrorType.APPLICATION,
@@ -1309,7 +1364,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * It handles the invocations to the neutronvpn:getL3VPN RPC method.
      */
     @Override
-    public Future<RpcResult<GetL3VPNOutput>> getL3VPN(GetL3VPNInput input) {
+    public ListenableFuture<RpcResult<GetL3VPNOutput>> getL3VPN(GetL3VPNInput input) {
 
         GetL3VPNOutputBuilder opBuilder = new GetL3VPNOutputBuilder();
         SettableFuture<RpcResult<GetL3VPNOutput>> result = SettableFuture.create();
@@ -1332,6 +1387,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         if (vpn.getIpv4Family().getRouteDistinguisher() != null) {
                             vpns.add(vpn);
                         }
+                        if (vpn.getIpv6Family().getRouteDistinguisher() != null) {
+                            vpns.add(vpn);
+                        }
                     }
                 } else {
                     // No VPN present
@@ -1349,7 +1407,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 vpnIdentifier);
                 // eliminating implicitly created (router or VLAN provider external network specific) VPN from
                 // getL3VPN output
-                if (optionalVpn.isPresent() && optionalVpn.get().getIpv4Family().getRouteDistinguisher() != null) {
+                if (optionalVpn.isPresent() && optionalVpn.get().getIpv4Family().getRouteDistinguisher() != null
+                        || optionalVpn.get().getIpv6Family().getRouteDistinguisher() != null) {
                     vpns.add(optionalVpn.get());
                 } else {
                     result.set(
@@ -1362,22 +1421,35 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 Uuid vpnId = new Uuid(vpnInstance.getVpnInstanceName());
                 // create VpnMaps id
                 L3vpnInstancesBuilder l3vpn = new L3vpnInstancesBuilder();
-                List<String> rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
+                List<String> rd = Collections.EMPTY_LIST;
+                if (vpnInstance.getIpv4Family().getRouteDistinguisher() != null) {
+                    rd = vpnInstance.getIpv4Family().getRouteDistinguisher();
+                } else if (vpnInstance.getIpv6Family().getRouteDistinguisher() != null) {
+                    rd = vpnInstance.getIpv6Family().getRouteDistinguisher();
+                }
                 List<String> ertList = new ArrayList<>();
                 List<String> irtList = new ArrayList<>();
 
-                if (vpnInstance.getIpv4Family().getVpnTargets() != null) {
-                    List<VpnTarget> vpnTargetList = vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget();
-                    for (VpnTarget vpnTarget : vpnTargetList) {
-                        if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
-                            ertList.add(vpnTarget.getVrfRTValue());
-                        }
-                        if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
-                            irtList.add(vpnTarget.getVrfRTValue());
-                        }
-                        if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
-                            ertList.add(vpnTarget.getVrfRTValue());
-                            irtList.add(vpnTarget.getVrfRTValue());
+                if (vpnInstance.getIpv4Family().getVpnTargets() != null
+                        || vpnInstance.getIpv6Family().getVpnTargets() != null) {
+                    List<VpnTarget> vpnTargetList = Collections.EMPTY_LIST;
+                    if (!vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget().isEmpty()) {
+                        vpnTargetList = vpnInstance.getIpv4Family().getVpnTargets().getVpnTarget();
+                    } else if (!vpnInstance.getIpv6Family().getVpnTargets().getVpnTarget().isEmpty()) {
+                        vpnTargetList = vpnInstance.getIpv6Family().getVpnTargets().getVpnTarget();
+                    }
+                    if (!vpnTargetList.isEmpty()) {
+                        for (VpnTarget vpnTarget : vpnTargetList) {
+                            if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
+                                ertList.add(vpnTarget.getVrfRTValue());
+                            }
+                            if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
+                                irtList.add(vpnTarget.getVrfRTValue());
+                            }
+                            if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
+                                ertList.add(vpnTarget.getVrfRTValue());
+                                irtList.add(vpnTarget.getVrfRTValue());
+                            }
                         }
                     }
                 }
@@ -1394,8 +1466,16 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 vpnMapIdentifier);
                 if (optionalVpnMap.isPresent()) {
                     VpnMap vpnMap = optionalVpnMap.get();
-                    l3vpn.setRouterId(vpnMap.getRouterId()).setNetworkIds(vpnMap.getNetworkIds())
-                        .setTenantId(vpnMap.getTenantId()).setName(vpnMap.getName());
+                    List<Uuid> rtrIds = new ArrayList<>();
+                    if (vpnMap.getRouterIds() != null && !vpnMap.getRouterIds().isEmpty()) {
+                        for (RouterIds rtrId : vpnMap.getRouterIds()) {
+                            rtrIds.add(rtrId.getRouterId());
+                        }
+                    }
+                    l3vpn.setRouterIds(NeutronvpnUtils.getVpnInstanceRouterIdsList(rtrIds))
+                            .setNetworkIds(vpnMap.getNetworkIds()).setTenantId(vpnMap.getTenantId())
+                            .setName(vpnMap.getName());
+
                 }
                 l3vpnList.add(l3vpn.build());
             }
@@ -1414,7 +1494,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * It handles the invocations to the neutronvpn:deleteL3VPN RPC method.
      */
     @Override
-    public Future<RpcResult<DeleteL3VPNOutput>> deleteL3VPN(DeleteL3VPNInput input) {
+    public ListenableFuture<RpcResult<DeleteL3VPNOutput>> deleteL3VPN(DeleteL3VPNInput input) {
 
         DeleteL3VPNOutputBuilder opBuilder = new DeleteL3VPNOutputBuilder();
         SettableFuture<RpcResult<DeleteL3VPNOutput>> result = SettableFuture.create();
@@ -1427,6 +1507,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             RpcError error;
             String msg;
             try {
+                LOG.debug("L3VPN delete RPC: VpnID {}", vpn.getValue());
                 InstanceIdentifier<VpnInstance> vpnIdentifier =
                         InstanceIdentifier.builder(VpnInstances.class)
                             .child(VpnInstance.class, new VpnInstanceKey(vpn.getValue())).build();
@@ -1526,9 +1607,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 final Boolean isRouterInterface = port.getDeviceOwner()
                         .equals(NeutronConstants.DEVICE_OWNER_ROUTER_INF) ? true : false;
                 jobCoordinator.enqueueJob("PORT-" + portId.getValue(), () -> singletonList(
-                    txRunner.callWithNewWriteOnlyTransactionAndSubmit(wrtConfigTxn -> {
+                    txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, wrtConfigTxn -> {
                         Adjacencies portAdj = createPortIpAdjacencies(port, isRouterInterface, wrtConfigTxn, sn,
-                                vpnIface);
+                                    vpnIface);
                         if (vpnIface == null) {
                             LOG.trace("addSubnetToVpn: create new VpnInterface for Port {}", vpnInfName);
                             Set<Uuid> listVpn = new HashSet<>();
@@ -1539,9 +1620,9 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 listVpn.add(internetId);
                             }
                             writeVpnInterfaceToDs(listVpn,
-                                     vpnInfName, portAdj, isRouterInterface, wrtConfigTxn);
+                                    vpnInfName, portAdj, port.getNetworkId(), isRouterInterface, wrtConfigTxn);
                             if (sn.getRouterId() != null) {
-                                addToNeutronRouterInterfacesMap(sn.getRouterId(),portId.getValue());
+                                addToNeutronRouterInterfacesMap(sn.getRouterId(), portId.getValue());
                             }
                         } else {
                             LOG.trace("update VpnInterface for Port {} with adj {}", vpnInfName, portAdj);
@@ -1616,16 +1697,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 LOG.debug("withdrawing subnet IP {} from vpn-interface {}", sn.getSubnetIp(), portId.getValue());
                 final Port port = neutronvpnUtils.getNeutronPort(portId);
                 jobCoordinator.enqueueJob("PORT-" + portId.getValue(),
-                    () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-                        if (port != null) {
-                            withdrawPortIpFromVpnIface(vpnId, internetId, port, sn, tx);
-                        } else {
-                            LOG.warn(
-                                    "Cannot proceed with withdrawPortIpFromVpnIface for port {} in subnet {} since "
-                                            + "port is absent in Neutron config DS", portId.getValue(),
-                                    subnet.getValue());
-                        }
-                    })));
+                    () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
+                            CONFIGURATION, tx -> {
+                            if (port != null) {
+                                withdrawPortIpFromVpnIface(vpnId, internetId, port, sn, tx);
+                            } else {
+                                LOG.warn(
+                                        "Cannot proceed with withdrawPortIpFromVpnIface for port {} in subnet {} since "
+                                                + "port is absent in Neutron config DS", portId.getValue(),
+                                        subnet.getValue());
+                            }
+                        })));
             }
         }
         //update subnet-vpn association
@@ -1649,16 +1731,16 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
 
         jobCoordinator.enqueueJob("VPN-" + vpn.getValue(), () -> singletonList(
-            txRunner.callWithNewWriteOnlyTransactionAndSubmit(wrtConfigTxn -> {
+            txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, wrtConfigTxn -> {
                 if (isBeingAssociated) {
-                    updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(sm.getRouterInterfacePortId()),
-                                    true, true, wrtConfigTxn);
+                    updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(
+                            sm.getRouterInterfacePortId()), true, true, wrtConfigTxn);
                 } else {
-                    removeVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(sm.getRouterInterfacePortId()),
-                                        wrtConfigTxn, sm);
+                    removeVpnFromVpnInterface(vpn,
+                            neutronvpnUtils.getNeutronPort(sm.getRouterInterfacePortId()), wrtConfigTxn, sm);
                 }
-            }
-        )));
+                }
+            )));
 
         // Check for ports on this subnet and update association of
         // corresponding vpn-interfaces to internet vpn
@@ -1666,16 +1748,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         if (portList != null) {
             for (Uuid port : portList) {
                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
-                    port.getValue(), isBeingAssociated);
+                        port.getValue(), isBeingAssociated);
                 jobCoordinator.enqueueJob("PORT-" + port.getValue(),
-                    () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
-                        if (isBeingAssociated) {
-                            updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(port),
-                                    true, false, tx);
-                        } else {
-                            removeVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(port), tx, sm);
-                        }
-                    })));
+                    () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                        tx -> {
+                            if (isBeingAssociated) {
+                                updateVpnInterface(vpn, null, neutronvpnUtils.getNeutronPort(port),
+                                        true, false, tx);
+                            } else {
+                                removeVpnFromVpnInterface(vpn, neutronvpnUtils.getNeutronPort(port), tx, sm);
+                            }
+                        })));
             }
         }
     }
@@ -1697,7 +1780,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         //Update Router Interface first synchronously.
         //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
         ListenableFuture<Void> future =
-                txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> updateVpnInterface(newVpnId, oldVpnId,
+                txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                    tx -> updateVpnInterface(newVpnId, oldVpnId,
                         neutronvpnUtils.getNeutronPort(sn.getRouterInterfacePortId()),
                         isBeingAssociated, true, tx));
         Futures.addCallback(future, new FutureCallback<Void>() {
@@ -1711,7 +1795,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
                                 port.getValue(), isBeingAssociated);
                         jobCoordinator.enqueueJob("PORT-" + port.getValue(), () -> Collections.singletonList(
-                                txRunner.callWithNewWriteOnlyTransactionAndSubmit(
+                                txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
                                     tx -> updateVpnInterface(newVpnId, oldVpnId,
                                             neutronvpnUtils.getNeutronPort(port), isBeingAssociated, false,
                                             tx))));
@@ -1743,7 +1827,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 Optional<RouterInterfaces> optRouterInterfaces =
                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
                                 routerInterfacesId);
-                Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName))
+                Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
                     .setInterfaceId(interfaceName).build();
                 if (optRouterInterfaces.isPresent()) {
                     SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
@@ -1772,7 +1856,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 Optional<RouterInterfaces> optRouterInterfaces =
                         SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
                                 routerInterfacesId);
-                Interfaces routerInterface = new InterfacesBuilder().setKey(new InterfacesKey(interfaceName))
+                Interfaces routerInterface = new InterfacesBuilder().withKey(new InterfacesKey(interfaceName))
                     .setInterfaceId(interfaceName).build();
                 if (optRouterInterfaces.isPresent()) {
                     RouterInterfaces routerInterfaces = optRouterInterfaces.get();
@@ -1805,8 +1889,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     public void addInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
                                   HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
         for (Routes route : interVpnLinkRoutes) {
-            String nexthop = String.valueOf(route.getNexthop().getValue());
-            String destination = String.valueOf(route.getDestination().getValue());
+            String nexthop = route.getNexthop().stringValue();
+            String destination = route.getDestination().stringValue();
             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
                 AddStaticRouteInput rpcInput =
@@ -1831,7 +1915,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             } else {
                 // Any other case is a fault.
                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
-                        String.valueOf(route.getDestination().getValue()), nexthop);
+                        route.getDestination().stringValue(), nexthop);
                 continue;
             }
         }
@@ -1848,8 +1932,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     public void removeInterVpnRoutes(Uuid vpnName, List<Routes> interVpnLinkRoutes,
                                      HashMap<String, InterVpnLink> nexthopsXinterVpnLinks) {
         for (Routes route : interVpnLinkRoutes) {
-            String nexthop = String.valueOf(route.getNexthop().getValue());
-            String destination = String.valueOf(route.getDestination().getValue());
+            String nexthop = route.getNexthop().stringValue();
+            String destination = route.getDestination().stringValue();
             InterVpnLink interVpnLink = nexthopsXinterVpnLinks.get(nexthop);
             if (isNexthopTheOtherVpnLinkEndpoint(nexthop, vpnName.getValue(), interVpnLink)) {
                 RemoveStaticRouteInput rpcInput =
@@ -1862,7 +1946,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             } else {
                 // Any other case is a fault.
                 LOG.warn("route with destination {} and nexthop {} does not apply to any InterVpnLink",
-                        String.valueOf(route.getDestination().getValue()), nexthop);
+                        route.getDestination().stringValue(), nexthop);
                 continue;
             }
         }
@@ -1889,8 +1973,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
                 LOG.error("Incorrect input received for extra route. {}", route);
             } else {
-                String nextHop = String.valueOf(route.getNexthop().getValue());
-                String destination = String.valueOf(route.getDestination().getValue());
+                String nextHop = route.getNexthop().stringValue();
+                String destination = route.getDestination().stringValue();
                 if (!nextHop.equals(fixedIp)) {
                     LOG.trace("FixedIP {} is not extra route nexthop for destination {}", fixedIp, destination);
                     continue;
@@ -1909,10 +1993,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             final List<String> ipList = entry.getValue();
             Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
                     .setAdjacencyType(AdjacencyType.ExtraRoute).setNextHopIpList(ipList)
-                    .setKey(new AdjacencyKey(destination)).build();
+                    .withKey(new AdjacencyKey(destination)).build();
             adjList.add(erAdj);
         }
-        return  adjList;
+        return adjList;
     }
 
     protected void updateVpnInterfaceWithExtraRouteAdjacency(Uuid vpnId, List<Routes> routeList) {
@@ -1922,8 +2006,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (route == null || route.getNexthop() == null || route.getDestination() == null) {
                 LOG.error("Incorrect input received for extra route. {}", route);
             } else {
-                String nextHop = String.valueOf(route.getNexthop().getValue());
-                String destination = String.valueOf(route.getDestination().getValue());
+                String nextHop = route.getNexthop().stringValue();
+                String destination = route.getDestination().stringValue();
                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
                         nextHop);
                 if (infName != null) {
@@ -1945,7 +2029,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                             continue;
                         }
                         Adjacency erAdj = new AdjacencyBuilder().setIpAddress(destination)
-                            .setNextHopIpList(Collections.singletonList(nextHop)).setKey(new AdjacencyKey(destination))
+                            .setNextHopIpList(Collections.singletonList(nextHop)).withKey(new AdjacencyKey(destination))
                             .setAdjacencyType(AdjacencyType.ExtraRoute).build();
                         isLockAcquired = interfaceLock.tryLock(infName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
                         SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
@@ -1988,25 +2072,30 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     vpnId, routeList);
             return;
         }
-        List<Routes> routesError = new ArrayList();
+        String primaryRd = neutronvpnUtils.getVpnRd(vpnId.getValue());
+        if (primaryRd == null || primaryRd.equals(vpnId.getValue())) {
+            LOG.debug("checkAlarmExtraRoutes. vpn {} is not a BGPVPN. cancel checkExtraRoute",
+                    vpnId);
+            return;
+        }
         for (Routes route : routeList) {
             // count  the number of nexthops for each same route.getDestingation().getValue()
-            String destination = String.valueOf(route.getDestination().getValue());
-            String nextHop = String.valueOf(route.getNexthop().getValue());
-            List<String> nextHopList = new ArrayList();
+            String destination = route.getDestination().stringValue();
+            String nextHop = route.getNexthop().stringValue();
+            List<String> nextHopList = new ArrayList<>();
             nextHopList.add(nextHop);
             int nbNextHops = 0;
             for (Routes routeTmp : routeList) {
-                String routeDest = String.valueOf(routeTmp.getDestination().getValue());
+                String routeDest = routeTmp.getDestination().stringValue();
                 if (!destination.equals(routeDest)) {
                     continue;
                 }
-                String routeNextH = String.valueOf(routeTmp.getNexthop().getValue());
+                String routeNextH = routeTmp.getNexthop().stringValue();
                 if (nextHop.equals(routeNextH)) {
                     continue;
                 }
                 nbNextHops++;
-                nextHopList.add(new String(routeTmp.getNexthop().getValue()));
+                nextHopList.add(routeTmp.getNexthop().stringValue());
             }
             final List<String> rdList = new ArrayList<>();
             if (vpnInstance.getIpv4Family() != null
@@ -2028,7 +2117,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             String typeAlarm = "for vpnId: " + vpnId + " have exceeded next hops for prefixe";
 
             // 2. Router ID
-            Uuid routerUuid = neutronvpnUtils.getRouterforVpn(vpnId);
+            List<Uuid> routerUuidList = neutronvpnUtils.getRouterIdListforVpn(vpnId);
+            Uuid routerUuid = routerUuidList.get(0);
             StringBuilder detailsAlarm = new StringBuilder("routerUuid: ");
             detailsAlarm.append(routerUuid == null ? vpnId.toString() : routerUuid.getValue());
 
@@ -2041,7 +2131,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
             // 4. Prefix in question
             detailsAlarm.append(" for prefix: ");
-            detailsAlarm.append(route.getDestination().getValue());
+            detailsAlarm.append(route.getDestination().stringValue());
 
             // 5. List of NHs for the prefix
             detailsAlarm.append(" for nextHops: ");
@@ -2052,14 +2142,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
             if (rdList.size() < nbNextHops) {
                 neutronvpnAlarm.raiseNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
-                LOG.error("there are too many next hops for prefixe in vpn {}", vpnId);
-                routesError.add(route);
             } else {
                 neutronvpnAlarm.clearNeutronvpnAlarm(typeAlarm, detailsAlarm.toString());
             }
         }
-        //in routesError there are a few route raised in alarm, so they have not to be used
-        routeList.removeAll(routesError);
     }
 
     // TODO Clean up the exception handling
@@ -2068,8 +2154,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         for (Routes route : routeList) {
             if (route != null && route.getNexthop() != null && route.getDestination() != null) {
                 boolean isLockAcquired = false;
-                String nextHop = String.valueOf(route.getNexthop().getValue());
-                String destination = String.valueOf(route.getDestination().getValue());
+                String nextHop = route.getNexthop().stringValue();
+                String destination = route.getDestination().stringValue();
                 String infName = neutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(vpnId.getValue(),
                         nextHop);
                 if (infName == null) {
@@ -2114,11 +2200,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 VpnInterfaces.class).child(VpnInterface.class, new VpnInterfaceKey(infName)).build();
                         Adjacency newAdj = new AdjacencyBuilder(adjacency.get()).setIpAddress(destination)
                                 .setNextHopIpList(nextHopList)
-                                .setKey(new AdjacencyKey(destination))
+                                .withKey(new AdjacencyKey(destination))
                                 .build();
                         Adjacencies erAdjs =
                                 new AdjacenciesBuilder().setAdjacency(Collections.singletonList(newAdj)).build();
-                        VpnInterface vpnIf = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
+                        VpnInterface vpnIf = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
                                 .addAugmentation(Adjacencies.class, erAdjs).build();
                         SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
                                 vpnIfIdentifier, vpnIf);
@@ -2142,23 +2228,28 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    public void removeVpn(Uuid id) {
+    public void removeVpn(Uuid vpnId) {
         // read VPNMaps
-        VpnMap vpnMap = neutronvpnUtils.getVpnMap(id);
-        Uuid router = vpnMap != null ? vpnMap.getRouterId() : null;
+        VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
+        List<RouterIds> routerIdsList = vpnMap != null ? vpnMap.getRouterIds() : null;
         // dissociate router
-        if (router != null) {
-            dissociateRouterFromVpn(id, router);
-        }
-        // dissociate networks
-        if (!id.equals(router) && vpnMap.getNetworkIds() != null) {
-            dissociateNetworksFromVpn(id, vpnMap.getNetworkIds());
+        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());
+            }
         }
         // remove entire vpnMaps node
-        deleteVpnMapsNode(id);
+        deleteVpnMapsNode(vpnId);
 
         // remove vpn-instance
-        deleteVpnInstance(id);
+        deleteVpnInstance(vpnId);
+        LOG.debug("Deleted L3VPN with ID {}", vpnId.getValue());
     }
 
     private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
@@ -2170,14 +2261,20 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
         updateVpnMaps(vpnId, null, routerId, null, null);
         LOG.debug("Updating association of subnets to external vpn {}", vpnId.getValue());
-        List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
-        for (Uuid subnetId : routerSubnets) {
-            Subnetmap sn = updateVpnForSubnet(routerId, vpnId, subnetId, true);
-            if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(sn, vpnId)) {
-                neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
-                          NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()), true);
+        IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+        List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
+        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);
+            neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
+        }
 
         try {
             checkAndPublishRouterAssociatedtoVpnNotification(routerId, vpnId);
@@ -2208,22 +2305,21 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void dissociateRouterFromVpn(Uuid vpnId, Uuid routerId) {
 
-        List<Uuid> routerSubnets = neutronvpnUtils.getNeutronRouterSubnetIds(routerId);
-        boolean vpnInstanceIpVersionsRemoved = false;
-        IpVersionChoice vpnInstanceIpVersionsToRemove = IpVersionChoice.UNDEFINED;
-        for (Uuid subnetId : routerSubnets) {
-            Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
-            if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, vpnId)) {
-                vpnInstanceIpVersionsToRemove = vpnInstanceIpVersionsToRemove.addVersion(NeutronvpnUtils
-                        .getIpVersionFromString(sn.getSubnetIp()));
-                vpnInstanceIpVersionsRemoved = true;
+        List<Subnetmap> subMapList = neutronvpnUtils.getNeutronRouterSubnetMapList(routerId);
+        IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+        for (Subnetmap sn : subMapList) {
+            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());
-            updateVpnForSubnet(vpnId, routerId, subnetId, false);
+            updateVpnForSubnet(vpnId, routerId, sn.getId(), false);
         }
-
-        if (vpnInstanceIpVersionsRemoved) {
-            neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), vpnInstanceIpVersionsToRemove, false);
+        if (ipVersion != IpVersionChoice.UNDEFINED) {
+            LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {} ",
+                    ipVersion, vpnId);
+            neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion,
+                    false);
         }
         clearFromVpnMaps(vpnId, routerId, null);
         try {
@@ -2240,17 +2336,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * Parses and associates networks list with given VPN.
      *
      * @param vpnId Uuid of given VPN.
-     * @param networks List list of network Ids (Uuid), which will be associated.
+     * @param networkList List list of network Ids (Uuid), which will be associated.
      * @return list of formatted strings with detailed error messages.
      */
     @Nonnull
-    protected List<String> associateNetworksToVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networks) {
+    protected List<String> associateNetworksToVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networkList) {
         List<String> failedNwList = new ArrayList<>();
         HashSet<Uuid> passedNwList = new HashSet<>();
-        if (networks.isEmpty()) {
+        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",
-                                           vpnId.getValue()));
+                    vpnId.getValue()));
             return failedNwList;
         }
         VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
@@ -2268,7 +2364,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                                + "associated with", vpnId.getValue()));
                 return failedNwList;
             }
-            for (Uuid nw : networks) {
+            Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+            for (Uuid nw : networkList) {
                 Network network = neutronvpnUtils.getNeutronNetwork(nw);
                 if (network == null) {
                     LOG.error("associateNetworksToVpn: Network {} not found in ConfigDS", nw.getValue());
@@ -2276,7 +2373,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                                    nw.getValue()));
                     continue;
                 }
-                NetworkProviderExtension providerExtension = network.getAugmentation(NetworkProviderExtension.class);
+                NetworkProviderExtension providerExtension = network.augmentation(NetworkProviderExtension.class);
                 if (providerExtension.getSegments() != null && providerExtension.getSegments().size() > 1) {
                     LOG.error("associateNetworksToVpn: MultiSegmented network {} not supported in BGPVPN {}",
                               nw.getValue(), vpnId.getValue());
@@ -2292,79 +2389,95 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                                    + "another VPN %s", nw.getValue(), networkVpnId.getValue()));
                     continue;
                 }
-                if (neutronvpnUtils.getIsExternal(network)) {
-                    if (associateExtNetworkToVpn(vpnId, network)) {
-                        passedNwList.add(nw);
-                        continue;
-                    } else {
-                        LOG.error("associateNetworksToVpn: Failed to associate Provider Network {} with VPN {}",
-                                  nw.getValue(), vpnId.getValue());
-                        failedNwList.add(String.format("Failed to associate Provider Network %s with VPN %s",
-                                                       nw.getValue(), vpnId.getValue()));
-                        continue;
-                    }
+                if (NeutronvpnUtils.getIsExternal(network) && !associateExtNetworkToVpn(vpnId, network)) {
+                    LOG.error("associateNetworksToVpn: Failed to associate Provider Network {} with VPN {}",
+                            nw.getValue(), vpnId.getValue());
+                    failedNwList.add(String.format("Failed to associate Provider Network %s with VPN %s",
+                            nw.getValue(), vpnId.getValue()));
+                    continue;
                 }
-                List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
-                if (networkSubnets == null) {
+                List<Subnetmap> subnetmapList = neutronvpnUtils.getSubnetmapListFromNetworkId(nw);
+                if (subnetmapList == null || subnetmapList.isEmpty()) {
                     passedNwList.add(nw);
                     continue;
                 }
-                for (Uuid subnet : networkSubnets) {
-                    Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnet);
+                if (vpnManager.checkForOverlappingSubnets(nw, subnetmapList, vpnId, routeTargets, failedNwList)) {
+                    continue;
+                }
+                IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+                for (Subnetmap subnetmap : subnetmapList) {
+                    Uuid subnetId = subnetmap.getId();
+                    Uuid subnetVpnId = neutronvpnUtils.getVpnForSubnet(subnetId);
                     if (subnetVpnId != null) {
-                        LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {} as it is already "
-                                  + "associated", subnet.getValue(), subnetVpnId.getValue());
-                        failedNwList.add(String.format("Failed to associate subnet %s with VPN %s as it is already "
-                                                       + "associated", subnet.getValue(), vpnId.getValue()));
+                        LOG.error("associateNetworksToVpn: Failed to associate subnet {} with VPN {}"
+                                + " as it is already associated", subnetId.getValue(), subnetVpnId.getValue());
+                        failedNwList.add(String.format("Failed to associate subnet %s with VPN %s"
+                                + " as it is already associated", subnetId.getValue(), vpnId.getValue()));
                         continue;
                     }
-                    Subnetmap sm = neutronvpnUtils.getSubnetmap(subnet);
-                    if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToAdd(sm, vpnId)) {
-                        neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
-                                NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp()), true);
+                    IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(subnetmap.getSubnetIp());
+                    if (!ipVersion.isIpVersionChosen(ipVers)) {
+                        ipVersion = ipVersion.addVersion(ipVers);
                     }
-                    LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnet.getValue(), vpnId.getValue());
-                    addSubnetToVpn(vpnId, subnet, null);
-                    passedNwList.add(nw);
+                    if (!NeutronvpnUtils.getIsExternal(network)) {
+                        LOG.debug("associateNetworksToVpn: Add subnet {} to VPN {}", subnetId.getValue(),
+                                vpnId.getValue());
+                        addSubnetToVpn(vpnId, subnetId, null);
+                        vpnManager.updateRouteTargetsToSubnetAssociation(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);
+                    neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
                 }
+                passedNwList.add(nw);
             }
         } catch (ReadFailedException e) {
             LOG.error("associateNetworksToVpn: Failed to associate VPN {} with networks {}: ", vpnId.getValue(),
-                      networks, e);
+                    networkList, e);
             failedNwList.add(String.format("Failed to associate VPN %s with networks %s: %s", vpnId.getValue(),
-                                           networks, e));
+                    networkList, e));
         }
-        LOG.info("associateNetworksToVpn: update VPN {} with networks list: {}", vpnId.getValue(),
-                 passedNwList.toString());
-        updateVpnMaps(vpnId, null, null, null, new ArrayList<Uuid>(passedNwList));
+        updateVpnMaps(vpnId, null, null, null, new ArrayList<>(passedNwList));
+        LOG.info("Network(s) {} associated to L3VPN {} successfully", passedNwList.toString(), vpnId.getValue());
         return failedNwList;
     }
 
     private boolean associateExtNetworkToVpn(@Nonnull Uuid vpnId, @Nonnull Network extNet) {
+        if (!addExternalNetworkToVpn(extNet, vpnId)) {
+            return false;
+        }
         VpnInstanceOpDataEntry vpnOpDataEntry = neutronvpnUtils.getVpnInstanceOpDataEntryFromVpnId(vpnId.getValue());
         if (vpnOpDataEntry == null) {
             LOG.error("associateExtNetworkToVpn: can not find VpnOpDataEntry for VPN {}", vpnId.getValue());
             return false;
         }
-        if (!addExternalNetworkToVpn(extNet, vpnId)) {
-            return false;
-        }
         if (!vpnOpDataEntry.getBgpvpnType().equals(BgpvpnType.BGPVPNInternet)) {
             LOG.info("associateExtNetworkToVpn: set type {} for VPN {}", BgpvpnType.BGPVPNInternet, vpnId.getValue());
             neutronvpnUtils.updateVpnInstanceOpWithType(BgpvpnType.BGPVPNInternet, vpnId);
         }
-        for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet)) {
+        IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+        for (Uuid snId: neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
             if (sm == null) {
                 LOG.error("associateExtNetworkToVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
                 continue;
             }
-            updateVpnInternetForSubnet(sm, vpnId, true);
-            if (!(vpnOpDataEntry.isIpv6Configured())
-                    && (NeutronvpnUtils.getIpVersionFromString(sm.getSubnetIp()) == IpVersionChoice.IPV6)) {
-                LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
-                neutronvpnUtils.updateVpnInstanceWithFallback(vpnId.getValue(), true);
+            IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
+                updateVpnInternetForSubnet(sm, vpnId, true);
             }
+            if (!ipVersion.isIpVersionChosen(ipVers)) {
+                ipVersion = ipVersion.addVersion(ipVers);
+            }
+        }
+        if (ipVersion != IpVersionChoice.UNDEFINED && ipVersion != IpVersionChoice.IPV4) {
+            neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, true);
+            LOG.info("associateExtNetworkToVpn: add IPv6 Internet default route in VPN {}", vpnId.getValue());
+            neutronvpnUtils.updateVpnInstanceWithFallback(vpnId, true);
         }
         return true;
     }
@@ -2373,25 +2486,30 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * Parses and disassociates networks list from given VPN.
      *
      * @param vpnId Uuid of given VPN.
-     * @param networks List list of network Ids (Uuid), which will be disassociated.
+     * @param networkList List list of network Ids (Uuid), which will be disassociated.
      * @return list of formatted strings with detailed error messages.
      */
     @Nonnull
-    protected List<String> dissociateNetworksFromVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networks) {
+    protected List<String> dissociateNetworksFromVpn(@Nonnull Uuid vpnId, @Nonnull List<Uuid> networkList) {
         List<String> failedNwList = new ArrayList<>();
         HashSet<Uuid> passedNwList = new HashSet<>();
-        if (networks.isEmpty()) {
+        if (networkList.isEmpty()) {
             LOG.error("dissociateNetworksFromVpn: Failed as networks list is empty");
             failedNwList.add(String.format("Failed to disassociate networks from VPN %s as networks list is empty",
                              vpnId.getValue()));
             return failedNwList;
         }
-        for (Uuid nw : networks) {
+        for (Uuid nw : networkList) {
+            List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
+            if (networkSubnets == null) {
+                passedNwList.add(nw);
+                continue;
+            }
             Network network = neutronvpnUtils.getNeutronNetwork(nw);
             if (network == null) {
                 LOG.error("dissociateNetworksFromVpn: Network {} not found in ConfigDS");
                 failedNwList.add(String.format("Failed to disassociate network %s as is not found in ConfigDS",
-                                               nw.getValue()));
+                        nw.getValue()));
                 continue;
             }
             Uuid networkVpnId = neutronvpnUtils.getVpnForNetwork(nw);
@@ -2405,11 +2523,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 LOG.error("dissociateNetworksFromVpn: Network {} is associated to another VPN {} instead of given {}",
                           nw.getValue(), networkVpnId.getValue(), vpnId.getValue());
                 failedNwList.add(String.format("Failed to disassociate network %s as it is associated to another "
-                                               + "vpn %s instead of given %s", nw.getValue(), networkVpnId.getValue(),
-                                               vpnId.getValue()));
+                                + "vpn %s instead of given %s", nw.getValue(), networkVpnId.getValue(),
+                                vpnId.getValue()));
                 continue;
             }
-            if (neutronvpnUtils.getIsExternal(network)) {
+            if (NeutronvpnUtils.getIsExternal(network)) {
                 if (disassociateExtNetworkFromVpn(vpnId, network)) {
                     passedNwList.add(nw);
                     continue;
@@ -2421,28 +2539,30 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     continue;
                 }
             }
-            List<Uuid> networkSubnets = neutronvpnUtils.getSubnetIdsFromNetworkId(nw);
-            if (networkSubnets == null) {
-                passedNwList.add(nw);
-                continue;
-            }
+            Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+            IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
             for (Uuid subnet : networkSubnets) {
-                Subnetmap sm = neutronvpnUtils.getSubnetmap(subnet);
-                if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sm, vpnId)) {
-                    IpVersionChoice ipVersionsToRemove = IpVersionChoice.UNDEFINED;
-                    IpVersionChoice ipVersion = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
-                    neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
-                        ipVersionsToRemove.addVersion(ipVersion), false);
+                Subnetmap subnetmap = neutronvpnUtils.getSubnetmap(subnet);
+                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 (ipVersion != IpVersionChoice.UNDEFINED) {
+                LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
+                        ipVersion, vpnId);
+                neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
+            }
         }
-        LOG.info("dissociateNetworksFromVpn: Withdraw networks list {} from VPN {}", networks.toString(),
-                 vpnId.getValue());
-        clearFromVpnMaps(vpnId, null, new ArrayList<Uuid>(passedNwList));
+        clearFromVpnMaps(vpnId, null, new ArrayList<>(passedNwList));
+        LOG.info("Network(s) {} disassociated from L3VPN {} successfully", passedNwList.toString(),
+                vpnId.getValue());
         return failedNwList;
     }
 
@@ -2453,28 +2573,41 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         // check, if there is another Provider Networks associated with given VPN
         List<Uuid> vpnNets = getNetworksForVpn(vpnId);
         if (vpnNets != null) {
+            //Remove currently disassociated network from the list
+            vpnNets.remove(extNet.getUuid());
             for (Uuid netId : vpnNets) {
-                if (neutronvpnUtils.getIsExternal(getNeutronNetwork(netId))) {
+                if (NeutronvpnUtils.getIsExternal(getNeutronNetwork(netId))) {
                     LOG.error("dissociateExtNetworkFromVpn: Internet VPN {} is still associated with Provider Network "
-                              + "{}", vpnId.getValue(), netId.getValue());
+                            + "{}", vpnId.getValue(), netId.getValue());
                     return true;
                 }
             }
         }
+        //Set VPN Type is BGPVPNExternal from BGPVPNInternet
         LOG.info("disassociateExtNetworkFromVpn: set type {} for VPN {}",
                 VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal, vpnId.getValue());
         neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal, vpnId);
-        for (Uuid snId : neutronvpnUtils.getPrivateSubnetsToExport(extNet)) {
+        IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
+        for (Uuid snId : neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
             if (sm == null) {
                 LOG.error("disassociateExtNetworkFromVpn: can not find subnet with Id {} in ConfigDS", snId.getValue());
                 continue;
             }
-            updateVpnInternetForSubnet(sm, vpnId, false);
+            IpVersionChoice ipVers = neutronvpnUtils.getIpVersionFromString(sm.getSubnetIp());
+            if (ipVers.isIpVersionChosen(IpVersionChoice.IPV6)) {
+                updateVpnInternetForSubnet(sm, vpnId, false);
+            }
+            if (!ipVersion.isIpVersionChosen(ipVers)) {
+                ipVersion = ipVersion.addVersion(ipVers);
+            }
+        }
+        if (ipVersion != IpVersionChoice.UNDEFINED && ipVersion != IpVersionChoice.IPV4) {
+            neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
+            LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}",
+                    vpnId.getValue());
+            neutronvpnUtils.updateVpnInstanceWithFallback(vpnId, false);
         }
-        neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), IpVersionChoice.IPV6, false);
-        LOG.info("disassociateExtNetworkFromVpn: withdraw IPv6 Internet default route from VPN {}", vpnId.getValue());
-        neutronvpnUtils.updateVpnInstanceWithFallback(vpnId.getValue(), false);
         return true;
     }
 
@@ -2484,16 +2617,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public Future<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
+    public ListenableFuture<RpcResult<AssociateNetworksOutput>> associateNetworks(AssociateNetworksInput input) {
 
         AssociateNetworksOutputBuilder opBuilder = new AssociateNetworksOutputBuilder();
         SettableFuture<RpcResult<AssociateNetworksOutput>> result = SettableFuture.create();
-        LOG.debug("associateNetworks {}", input);
         StringBuilder returnMsg = new StringBuilder();
         Uuid vpnId = input.getVpnId();
 
         try {
             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
+                LOG.debug("associateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
+                        input.getNetworkId().toString());
                 List<Uuid> netIds = input.getNetworkId();
                 if (netIds != null && !netIds.isEmpty()) {
                     List<String> failed = associateNetworksToVpn(vpnId, netIds);
@@ -2525,58 +2659,60 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
      * It handles the invocations to the neutronvpn:associateRouter RPC method.
      */
     @Override
-    // TODO Clean up the exception handling
-    @SuppressWarnings("checkstyle:IllegalCatch")
-    public Future<RpcResult<Void>> associateRouter(AssociateRouterInput input) {
+    public ListenableFuture<RpcResult<AssociateRouterOutput>> associateRouter(AssociateRouterInput input) {
 
-        SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        SettableFuture<RpcResult<AssociateRouterOutput>> result = SettableFuture.create();
         LOG.debug("associateRouter {}", input);
         StringBuilder returnMsg = new StringBuilder();
         Uuid vpnId = input.getVpnId();
-        Uuid routerId = input.getRouterId();
-        try {
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter.input.RouterIds>
+                routerIds = input.getRouterIds();
+        Preconditions.checkArgument(!routerIds.isEmpty(), "associateRouter: RouterIds list is empty!");
+        Preconditions.checkNotNull(vpnId, "associateRouter; VpnId not found!");
+        Preconditions.checkNotNull(vpnId, "associateRouter; RouterIds not found!");
+        for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.associaterouter.input
+                .RouterIds routerId : routerIds) {
             VpnMap vpnMap = neutronvpnUtils.getVpnMap(vpnId);
-            Router rtr = neutronvpnUtils.getNeutronRouter(routerId);
+            Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
             if (vpnMap != null) {
                 if (rtr != null) {
-                    Uuid extVpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
-                    if (vpnMap.getRouterId() != null) {
+                    Uuid extVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
+                    if (vpnMap.getRouterIds() != null && vpnMap.getRouterIds().size() > 1) {
                         returnMsg.append("vpn ").append(vpnId.getValue()).append(" already associated to router ")
-                                .append(vpnMap.getRouterId().getValue());
+                                .append(routerId.getRouterId());
                     } else if (extVpnId != null) {
-                        returnMsg.append("router ").append(routerId.getValue()).append(" already associated to "
-                            + "another VPN ").append(extVpnId.getValue());
+                        returnMsg.append("router ").append(routerId.getRouterId()).append(" already associated to "
+                                + "another VPN ").append(extVpnId.getValue());
                     } else {
-                        associateRouterToVpn(vpnId, routerId);
+                        LOG.debug("associateRouter RPC: VpnId {}, routerId {}", vpnId.getValue(),
+                                routerId.getRouterId());
+                        associateRouterToVpn(vpnId, routerId.getRouterId());
                     }
                 } else {
-                    returnMsg.append("router not found : ").append(routerId.getValue());
+                    returnMsg.append("router not found : ").append(routerId.getRouterId());
                 }
             } else {
                 returnMsg.append("VPN not found : ").append(vpnId.getValue());
             }
             if (returnMsg.length() != 0) {
-                result.set(RpcResultBuilder.<Void>failed().withWarning(ErrorType.PROTOCOL, "invalid-value",
-                        formatAndLog(LOG::error, "associate router to vpn {} failed due to {}", routerId.getValue(),
-                                returnMsg)).build());
+                result.set(RpcResultBuilder.<AssociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
+                        "invalid-value", formatAndLog(LOG::error, "associate router to vpn {} failed "
+                                + "due to {}", routerId.getRouterId(), returnMsg)).build());
             } else {
-                result.set(RpcResultBuilder.<Void>success().build());
+                result.set(RpcResultBuilder.success(new AssociateRouterOutputBuilder().build()).build());
             }
-        } catch (Exception ex) {
-            result.set(RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION,
-                    formatAndLog(LOG::error, "associate router {} to vpn {} failed due to {}", routerId.getValue(),
-                            vpnId.getValue(), ex.getMessage(), ex)).build());
         }
         LOG.debug("associateRouter returns..");
         return result;
     }
 
-    /** It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
+    /**
+     * It handles the invocations to the neutronvpn:getFixedIPsForNeutronPort RPC method.
      */
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public Future<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
+    public ListenableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> getFixedIPsForNeutronPort(
         GetFixedIPsForNeutronPortInput input) {
         GetFixedIPsForNeutronPortOutputBuilder opBuilder = new GetFixedIPsForNeutronPortOutputBuilder();
         SettableFuture<RpcResult<GetFixedIPsForNeutronPortOutput>> result = SettableFuture.create();
@@ -2588,7 +2724,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (port != null) {
                 List<FixedIps> fixedIPs = port.getFixedIps();
                 for (FixedIps ip : fixedIPs) {
-                    fixedIPList.add(String.valueOf(ip.getIpAddress().getValue()));
+                    fixedIPList.add(ip.getIpAddress().stringValue());
                 }
             } else {
                 returnMsg.append("neutron port: ").append(portId.getValue()).append(" not found");
@@ -2618,7 +2754,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public Future<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
+    public ListenableFuture<RpcResult<DissociateNetworksOutput>> dissociateNetworks(DissociateNetworksInput input) {
 
         DissociateNetworksOutputBuilder opBuilder = new DissociateNetworksOutputBuilder();
         SettableFuture<RpcResult<DissociateNetworksOutput>> result = SettableFuture.create();
@@ -2629,6 +2765,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
         try {
             if (neutronvpnUtils.getVpnMap(vpnId) != null) {
+                LOG.debug("dissociateNetworks RPC: VpnId {}, networkList {}", vpnId.getValue(),
+                        input.getNetworkId().toString());
                 List<Uuid> netIds = input.getNetworkId();
                 if (netIds != null && !netIds.isEmpty()) {
                     List<String> failed = dissociateNetworksFromVpn(vpnId, netIds);
@@ -2642,7 +2780,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             if (returnMsg.length() != 0) {
                 opBuilder.setResponse(
                         "ErrorType: PROTOCOL, ErrorTag: invalid-value, ErrorMessage: " + formatAndLog(LOG::error,
-                                "dissociate Networks to vpn {} failed due to {}", vpnId.getValue(), returnMsg));
+                                "dissociate Networks to vpn {} failed due to {}", vpnId.getValue(),
+                                returnMsg));
                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().withResult(opBuilder.build()).build());
             } else {
                 result.set(RpcResultBuilder.<DissociateNetworksOutput>success().build());
@@ -2662,53 +2801,61 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     @Override
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public Future<RpcResult<Void>> dissociateRouter(DissociateRouterInput input) {
+    public ListenableFuture<RpcResult<DissociateRouterOutput>> dissociateRouter(DissociateRouterInput input) {
 
-        SettableFuture<RpcResult<Void>> result = SettableFuture.create();
+        SettableFuture<RpcResult<DissociateRouterOutput>> result = SettableFuture.create();
 
         LOG.debug("dissociateRouter {}", input);
         StringBuilder returnMsg = new StringBuilder();
         Uuid vpnId = input.getVpnId();
-        Uuid routerId = input.getRouterId();
-        try {
-            if (neutronvpnUtils.getVpnMap(vpnId) != null) {
-                if (routerId != null) {
-                    Router rtr = neutronvpnUtils.getNeutronRouter(routerId);
-                    if (rtr != null) {
-                        Uuid routerVpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
-                        if (vpnId.equals(routerVpnId)) {
-                            dissociateRouterFromVpn(vpnId, routerId);
-                        } else {
+        List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
+                .RouterIds> routerIdList = input.getRouterIds();
+        String routerIdsString = "";
+        Preconditions.checkArgument(!routerIdList.isEmpty(), "dissociateRouter: RouterIds list is empty!");
+        Preconditions.checkNotNull(vpnId, "dissociateRouter: vpnId not found!");
+        Preconditions.checkNotNull(routerIdList, "dissociateRouter: routerIdList not found!");
+        if (neutronvpnUtils.getVpnMap(vpnId) != null) {
+            for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.dissociaterouter.input
+                    .RouterIds routerId : routerIdList) {
+                try {
+                    if (routerId != null) {
+                        routerIdsString += routerId.getRouterId() + ", ";
+                        Router rtr = neutronvpnUtils.getNeutronRouter(routerId.getRouterId());
+                        if (rtr != null) {
+                            Uuid routerVpnId = neutronvpnUtils.getVpnForRouter(routerId.getRouterId(), true);
                             if (routerVpnId == null) {
-                                returnMsg.append("input router ").append(routerId.getValue())
-                                    .append(" not associated to any vpn yet");
+                                returnMsg.append("input router ").append(routerId.getRouterId())
+                                        .append(" not associated to any vpn yet");
+                            } else if (vpnId.equals(routerVpnId)) {
+                                dissociateRouterFromVpn(vpnId, routerId.getRouterId());
                             } else {
-                                returnMsg.append("input router ").append(routerId.getValue())
-                                    .append(" associated to vpn ")
-                                    .append(routerVpnId.getValue()).append("instead of the vpn given as input");
+                                returnMsg.append("input router ").append(routerId.getRouterId())
+                                        .append(" associated to vpn ")
+                                        .append(routerVpnId.getValue()).append("instead of the vpn given as input");
                             }
+                        } else {
+                            returnMsg.append("router not found : ").append(routerId.getRouterId());
                         }
+                    }
+                    if (returnMsg.length() != 0) {
+                        result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withWarning(ErrorType.PROTOCOL,
+                                "invalid-value", formatAndLog(LOG::error, "dissociate router {} to "
+                                                + "vpn {} failed due to {}", routerId.getRouterId(), vpnId.getValue(),
+                                        returnMsg)).build());
                     } else {
-                        returnMsg.append("router not found : ").append(routerId.getValue());
+                        result.set(RpcResultBuilder.success(new DissociateRouterOutputBuilder().build()).build());
                     }
+                } catch (Exception ex) {
+                    result.set(RpcResultBuilder.<DissociateRouterOutput>failed().withError(ErrorType.APPLICATION,
+                            formatAndLog(LOG::error, "disssociate router {} to vpn {} failed due to {}",
+                                    routerId.getRouterId(), vpnId.getValue(), ex.getMessage(), ex)).build());
                 }
-            } else {
-                returnMsg.append("VPN not found : ").append(vpnId.getValue());
             }
-            if (returnMsg.length() != 0) {
-                result.set(RpcResultBuilder.<Void>failed().withWarning(ErrorType.PROTOCOL, "invalid-value",
-                        formatAndLog(LOG::error, "dissociate router {} to vpn {} failed due to {}", routerId.getValue(),
-                                vpnId.getValue(), returnMsg)).build());
-            } else {
-                result.set(RpcResultBuilder.<Void>success().build());
-            }
-        } catch (Exception ex) {
-            result.set(RpcResultBuilder.<Void>failed().withError(ErrorType.APPLICATION,
-                    formatAndLog(LOG::error, "disssociate router {} to vpn {} failed due to {}", routerId.getValue(),
-                            vpnId.getValue(), ex.getMessage(), ex)).build());
+        } else {
+            returnMsg.append("VPN not found : ").append(vpnId.getValue());
         }
-        LOG.debug("dissociateRouter returns..");
 
+        LOG.debug("dissociateRouter returns..");
         return result;
     }
 
@@ -2781,7 +2928,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         result.add("-------------------------------------------------------------------------------------------");
         InstanceIdentifier<Ports> portidentifier = InstanceIdentifier.create(Neutron.class).child(Ports.class);
 
-        Optional<Ports> ports = syncReadOptional(dataBroker, CONFIGURATION, portidentifier);
+        Optional<Ports> ports = syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION, portidentifier);
         if (ports.isPresent() && ports.get().getPort() != null) {
             for (Port port : ports.get().getPort()) {
                 List<FixedIps> fixedIPs = port.getFixedIps();
@@ -2839,7 +2986,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             result.add("");
             List<L3vpnInstances> vpnList = rpcResult.getResult().getL3vpnInstances();
             for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn
-                        .rev150602.VpnInstance vpn : vpnList) {
+                    .rev150602.VpnInstance vpn : vpnList) {
                 String tenantId = vpn.getTenantId() != null ? vpn.getTenantId().getValue()
                         : "\"                 " + "                  \"";
                 result.add(String.format(" %-37s %-37s %-7s ", vpn.getId().getValue(), tenantId,
@@ -2891,7 +3038,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             return;
         }
 
-        ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
             for (String elanInterface : extElanInterfaces) {
                 createExternalVpnInterface(extNetId, elanInterface, tx);
             }
@@ -2906,32 +3053,33 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             LOG.error("No external ports attached for external network {}", extNetId.getValue());
             return;
         }
-        ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+        ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
             for (String elanInterface : extElanInterfaces) {
                 InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils
                         .buildVpnInterfaceIdentifier(elanInterface);
                 LOG.info("Removing vpn interface {}", elanInterface);
-                tx.delete(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
+                tx.delete(vpnIfIdentifier);
             }
         }), LOG, "Error removing external VPN interfaces for {}", extNetId);
     }
 
-    private void createExternalVpnInterface(Uuid vpnId, String infName, WriteTransaction wrtConfigTxn) {
-        writeVpnInterfaceToDs(Collections.singletonList(vpnId), infName, null,
+    private void createExternalVpnInterface(Uuid vpnId, String infName,
+                                            TypedWriteTransaction<Datastore.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,
-            Boolean isRouterInterface, WriteTransaction wrtConfigTxn) {
+            Uuid networkUuid, Boolean isRouterInterface, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
         if (vpnIdList.isEmpty() || infName == null) {
-            LOG.error("vpn id or interface is null");
+            LOG.error("vpnid is empty or interface({}) is null", infName);
             return;
         }
         if (wrtConfigTxn == null) {
-            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
-                tx -> writeVpnInterfaceToDs(vpnIdList, infName, adjacencies, isRouterInterface, tx)), LOG,
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
+                tx -> writeVpnInterfaceToDs(vpnIdList, infName, adjacencies, networkUuid, isRouterInterface, tx)), LOG,
                 "Error writing VPN interface");
             return;
         }
@@ -2943,30 +3091,42 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
 
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
-        VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
+        VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().withKey(new VpnInterfaceKey(infName))
                 .setName(infName)
                 .setVpnInstanceNames(vpnIdListStruct)
                 .setRouterInterface(isRouterInterface);
+        LOG.info("Network Id is {}", networkUuid);
+        if (networkUuid != null) {
+            Network portNetwork = neutronvpnUtils.getNeutronNetwork(networkUuid);
+            ProviderTypes providerType = NeutronvpnUtils.getProviderNetworkType(portNetwork);
+            NetworkAttributes.NetworkType networkType = (providerType != null)
+                    ? NetworkAttributes.NetworkType.valueOf(providerType.getName()) : null;
+            String segmentationId = NeutronvpnUtils.getSegmentationIdFromNeutronNetwork(portNetwork);
+            vpnb.setNetworkId(networkUuid).setNetworkType(networkType)
+                .setSegmentationId(segmentationId != null ? Long.parseLong(segmentationId) : 0L);
+        }
+
         if (adjacencies != null) {
             vpnb.addAugmentation(Adjacencies.class, adjacencies);
         }
         VpnInterface vpnIf = vpnb.build();
         try {
             LOG.info("Creating vpn interface {}", vpnIf);
-            wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIf);
+            wrtConfigTxn.put(vpnIfIdentifier, vpnIf);
         } catch (Exception ex) {
             LOG.error("Creation of vpninterface {} failed", infName, ex);
         }
     }
 
     private void updateVpnInterfaceWithAdjacencies(Uuid vpnId, String infName, Adjacencies adjacencies,
-            WriteTransaction wrtConfigTxn) {
+                                                   TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
         if (vpnId == null || infName == null) {
             LOG.error("vpn id or interface is null");
             return;
         }
         if (wrtConfigTxn == null) {
-            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+            LOG.error("updateVpnInterfaceWithAdjancies called with wrtConfigTxn as null");
+            ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
                 updateVpnInterfaceWithAdjacencies(vpnId, infName, adjacencies, tx);
             }), LOG, "Error updating VPN interface with adjacencies");
             return;
@@ -2994,7 +3154,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     List<VpnInstanceNames> listVpnInstances = new ArrayList<>(
                         optionalVpnInterface.get().getVpnInstanceNames());
                     if (listVpnInstances.isEmpty() || !VpnHelper
-                        .doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(),listVpnInstances)) {
+                        .doesVpnInterfaceBelongToVpnInstance(vpnId.getValue(), listVpnInstances)) {
                         VpnInstanceNames vpnInstance = VpnHelper
                              .getVpnInterfaceVpnInstanceNames(vpnId.getValue(), AssociatedSubnetType.V4AndV6Subnets);
                         listVpnInstances.add(vpnInstance);
@@ -3008,7 +3168,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     vpnIfBuilder.setVpnInstanceNames(listVpnInstances);
                 }
                 LOG.info("Updating vpn interface {} with new adjacencies", infName);
-                wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIfBuilder.build());
+                wrtConfigTxn.put(vpnIfIdentifier, vpnIfBuilder.build());
             }
         } catch (IllegalStateException | ReadFailedException ex) {
             LOG.error("Update of vpninterface {} failed", infName, ex);
@@ -3046,24 +3206,24 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     }
 
     @Override
-    public Future<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
+    public ListenableFuture<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
         return neutronEvpnManager.createEVPN(input);
     }
 
     @Override
-    public Future<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
+    public ListenableFuture<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
         return neutronEvpnManager.getEVPN(input);
     }
 
     @Override
-    public Future<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
+    public ListenableFuture<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
         return neutronEvpnManager.deleteEVPN(input);
     }
 
     private boolean addExternalNetworkToVpn(Network extNet, Uuid vpnId) {
         Uuid extNetId = extNet.getUuid();
         InstanceIdentifier<Networks> extNetIdentifier = InstanceIdentifier.builder(ExternalNetworks.class)
-            .child(Networks.class, new NetworksKey(extNetId)).build();
+                .child(Networks.class, new NetworksKey(extNetId)).build();
 
         try {
             Optional<Networks> optionalExtNets =
@@ -3103,7 +3263,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 builder = new NetworksBuilder(optionalNets.get());
             } else {
                 LOG.error("removeExternalNetworkFromVpn: Provider Network {} is not present in the ConfigDS",
-                          extNetId.getValue());
+                        extNetId.getValue());
                 return false;
             }
             builder.setVpnid(null);
@@ -3114,7 +3274,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             return true;
         } catch (TransactionCommitFailedException | ReadFailedException ex) {
             LOG.error("removeExternalNetworkFromVpn: Failed to withdraw VPN Id from Provider Network node {}: ",
-                      extNetId.getValue(), ex);
+                    extNetId.getValue(), ex);
         }
         return false;
     }
@@ -3124,7 +3284,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataOptional;
         try {
             vpnInstanceOpDataOptional = SingleTransactionDataBroker
-                    .syncReadOptional(dataBroker, OPERATIONAL, neutronvpnUtils.getVpnOpDataIdentifier(primaryRd));
+                .syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                    neutronvpnUtils.getVpnOpDataIdentifier(primaryRd));
         } catch (ReadFailedException e) {
             LOG.error("getExistingOperationalVpn: Exception while checking operational status of vpn with rd {}",
                     primaryRd, e);
@@ -3157,4 +3318,30 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         logger.accept(message);
         return message;
     }
+
+    protected void addV6PrivateSubnetToExtNetwork(@Nonnull Uuid internetVpnId, @Nonnull Subnetmap subnetMap) {
+        //Set VPN type BGPVPNInternet from BGPVPNExternal
+        LOG.info("addV6PrivateSubnetToExtNetwork: set type {} for Internet VPN {}",
+                BgpvpnType.BGPVPNInternet, internetVpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceOpWithType(BgpvpnType.BGPVPNInternet, internetVpnId);
+        updateVpnInternetForSubnet(subnetMap, internetVpnId, true);
+
+        neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, true);
+        LOG.info("addV6PrivateSubnetToExtNetwork: Advertise IPv6 Private Subnet {} to Internet VPN {}",
+                subnetMap.getId(), internetVpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, true);
+    }
+
+    protected void removeV6PrivateSubnetToExtNetwork(@Nonnull Uuid internetVpnId, @Nonnull Subnetmap subnetMap) {
+        //Set VPN type BGPVPNExternal from BGPVPNInternet
+        LOG.info("removeV6PrivateSubnetToExtNetwork: set type {} for Internet VPN {}",
+                VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal, internetVpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal, internetVpnId);
+        updateVpnInternetForSubnet(subnetMap, internetVpnId, false);
+
+        neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6, false);
+        LOG.info("removeV6PrivateSubnetToExtNetwork: withdraw IPv6 Private subnet {} from Internet VPN {}",
+                subnetMap.getId(), internetVpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, false);
+    }
 }