Bug 7939 - CSIT Sporadic failures - Flow(s) missing in VPNService suite on
[netvirt.git] / vpnservice / neutronvpn / neutronvpn-impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronvpnManager.java
index 6ea44cbb5874197ac05d2d90a218fefeb5185111..dae53b2f6d45be84502a91bcf8d71b2cf17ddd31 100644 (file)
@@ -21,15 +21,23 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import javax.annotation.PreDestroy;
+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.TransactionCommitFailedException;
 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.netvirt.neutronvpn.evpn.manager.NeutronEvpnManager;
+import org.opendaylight.netvirt.neutronvpn.evpn.utils.NeutronEvpnUtils;
+import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
+import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.af.config.VpnTargets;
@@ -52,13 +60,18 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adj
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.AssociateNetworksInput;
 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.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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.CreateL3VPNOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteEVPNOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.DeleteL3VPNOutputBuilder;
@@ -66,6 +79,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.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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutputBuilder;
@@ -73,6 +88,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev15060
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.GetL3VPNOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkAttributes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpnBuilder;
@@ -102,6 +118,11 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.A
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveStaticRouteInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.OperationalPortStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.Features;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.Feature;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.extensions.rev160617.service.provider.features.attributes.features.FeatureKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
@@ -120,6 +141,7 @@ import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Singleton
 public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, EventListener {
     private static final Logger LOG = LoggerFactory.getLogger(NeutronvpnManager.class);
     private final DataBroker dataBroker;
@@ -128,41 +150,70 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     private final VpnRpcService vpnRpcService;
     private final NeutronFloatingToFixedIpMappingChangeListener floatingIpMapListener;
     private final IElanService elanService;
+    private final NeutronvpnConfig neutronvpnConfig;
+    private final IVpnManager vpnManager;
+    private final NeutronEvpnManager neutronEvpnManager;
+    private final NeutronEvpnUtils neutronEvpnUtils;
 
+    @Inject
     public NeutronvpnManager(
             final DataBroker dataBroker, final NotificationPublishService notiPublishService,
             final NeutronvpnNatManager vpnNatMgr, final VpnRpcService vpnRpcSrv, final IElanService elanService,
-            final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener) {
+            final NeutronFloatingToFixedIpMappingChangeListener neutronFloatingToFixedIpMappingChangeListener,
+            final NeutronvpnConfig neutronvpnConfig, final IVpnManager vpnManager) {
         this.dataBroker = dataBroker;
         nvpnNatManager = vpnNatMgr;
         notificationPublishService = notiPublishService;
         vpnRpcService = vpnRpcSrv;
         this.elanService = elanService;
         floatingIpMapListener = neutronFloatingToFixedIpMappingChangeListener;
+        this.neutronvpnConfig = neutronvpnConfig;
+        this.vpnManager = vpnManager;
+        neutronEvpnManager = new NeutronEvpnManager(dataBroker, this);
+        neutronEvpnUtils = new NeutronEvpnUtils(dataBroker, vpnManager);
+
+        configureFeatures();
     }
 
     @Override
+    @PreDestroy
     public void close() throws Exception {
         LOG.info("{} close", getClass().getSimpleName());
     }
 
+    private void configureFeatures() {
+        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();
+        try {
+            SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, iid, feature);
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Error configuring feature " + feature, e);
+        }
+    }
+
+    public String getOpenDaylightVniRangesConfig() {
+        return neutronvpnConfig.getOpendaylightVniRanges();
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void createSubnetmapNode(Uuid subnetId, String subnetIp, Uuid tenantId, Uuid networkId) {
+    protected void createSubnetmapNode(Uuid subnetId, String subnetIp, Uuid tenantId, Uuid networkId,
+                                       NetworkAttributes.NetworkType networkType, long segmentationId) {
         try {
             InstanceIdentifier<Subnetmap> subnetMapIdentifier = NeutronvpnUtils.buildSubnetMapIdentifier(subnetId);
             synchronized (subnetId.getValue().intern()) {
-                Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
-                        subnetMapIdentifier);
-                SubnetmapBuilder subnetmapBuilder = null;
+                Optional<Subnetmap> sn = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, subnetMapIdentifier);
                 if (sn.isPresent()) {
                     LOG.error("subnetmap node for subnet ID {} already exists, returning", subnetId.getValue());
                     return;
-                } else {
-                    subnetmapBuilder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId)
-                            .setSubnetIp(subnetIp).setTenantId(tenantId).setNetworkId(networkId);
-                    LOG.debug("Adding a new subnet node in Subnetmaps DS for subnet {}", subnetId.getValue());
                 }
+                SubnetmapBuilder subnetmapBuilder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId))
+                        .setId(subnetId).setSubnetIp(subnetIp).setTenantId(tenantId).setNetworkId(networkId)
+                        .setNetworkType(networkType).setSegmentationId(segmentationId);
+                LOG.debug("Adding a new subnet node in Subnetmaps DS for subnet {}", subnetId.getValue());
                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
                         subnetMapIdentifier, subnetmapBuilder.build());
             }
@@ -173,7 +224,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId) {
+    protected Subnetmap updateSubnetNode(Uuid subnetId, Uuid routerId, Uuid vpnId) {
         Subnetmap subnetmap = null;
         SubnetmapBuilder builder = null;
         InstanceIdentifier<Subnetmap> id = InstanceIdentifier.builder(Subnetmaps.class)
@@ -208,8 +259,8 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    protected void updateSubnetNodeWithFixedIps(Uuid subnetId, Uuid routerId,
-                                                Uuid routerInterfaceName, String fixedIp,
+    protected void updateSubnetNodeWithFixedIp(Uuid subnetId, Uuid routerId,
+                                                Uuid routerInterfacePortId, String fixedIp,
                                                 String routerIntfMacAddress) {
         Subnetmap subnetmap = null;
         SubnetmapBuilder builder = null;
@@ -220,33 +271,24 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 Optional<Subnetmap> sn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
                 if (sn.isPresent()) {
                     builder = new SubnetmapBuilder(sn.get());
-                    LOG.debug("WithRouterFixedIPs: Updating existing subnetmap node for subnet ID {}",
+                    LOG.debug("WithRouterFixedIP: Updating existing subnetmap node for subnet ID {}",
                         subnetId.getValue());
                 } else {
-                    builder = new SubnetmapBuilder().setKey(new SubnetmapKey(subnetId)).setId(subnetId);
-                    LOG.debug("WithRouterFixedIPs: creating new subnetmap node for subnet ID {}",
+                    LOG.error("WithRouterFixedIP: subnetmap node for subnet {} does not exist, returning ",
                         subnetId.getValue());
+                    return;
                 }
                 builder.setRouterId(routerId);
-                builder.setRouterInterfaceName(routerInterfaceName);
+                builder.setRouterInterfacePortId(routerInterfacePortId);
                 builder.setRouterIntfMacAddress(routerIntfMacAddress);
-                if (fixedIp != null) {
-                    List<String> fixedIps = builder.getRouterInterfaceFixedIps();
-                    if (fixedIps == null) {
-                        fixedIps = new ArrayList<>();
-                    }
-                    fixedIps.add(fixedIp);
-                    builder.setRouterInterfaceFixedIps(fixedIps);
-                } else {
-                    builder.setRouterInterfaceFixedIps(null);
-                }
+                builder.setRouterInterfaceFixedIp(fixedIp);
                 subnetmap = builder.build();
-                LOG.debug("WithRouterFixedIPs Creating/Updating subnetMap node for Router FixedIps: {} ",
+                LOG.debug("WithRouterFixedIP Creating/Updating subnetMap node for Router FixedIp: {} ",
                     subnetId.getValue());
                 SingleTransactionDataBroker.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id, subnetmap);
             }
         } catch (Exception e) {
-            LOG.error("WithRouterFixedIPs: Updation of subnetMap for Router FixedIps failed for node: {}",
+            LOG.error("WithRouterFixedIP: Updation of subnetMap for Router FixedIp failed for node: {}",
                 subnetId.getValue());
         }
     }
@@ -392,6 +434,28 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
+    public void updateVpnInstanceWithRDs(String vpnInstanceId, final List<String> rds) {
+        InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
+            .child(VpnInstance.class, new VpnInstanceKey(vpnInstanceId)).build();
+        Optional<VpnInstance> vpnInstanceConfig =
+            NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier);
+        if (!vpnInstanceConfig.isPresent()) {
+            LOG.debug("No VpnInstance present under config vpnInstance:{}", vpnInstanceId);
+            return;
+        }
+        VpnInstance vpnInstance = vpnInstanceConfig.get();
+        VpnInstanceBuilder updateVpnInstanceBuilder = new VpnInstanceBuilder(vpnInstance);
+        Ipv4FamilyBuilder ipv4FamilyBuilder = new Ipv4FamilyBuilder(vpnInstance.getIpv4Family());
+        updateVpnInstanceBuilder.setIpv4Family(ipv4FamilyBuilder.setRouteDistinguisher(rds).build());
+        LOG.debug("Updating Config vpn-instance: {} with the list of RDs: {}", vpnInstanceId,rds);
+        try {
+            SingleTransactionDataBroker.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdentifier,
+                    updateVpnInstanceBuilder.build());
+        } catch (TransactionCommitFailedException ex) {
+            LOG.warn("Error configuring feature ", ex);
+        }
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     private void updateVpnInstanceNode(String vpnName, List<String> rd, List<String> irt, List<String> ert,
@@ -690,7 +754,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void updateVpnInterface(Uuid vpnId, Uuid oldVpnId, Port port, boolean isBeingAssociated,
-                                      boolean isSubnetIp) {
+                                      boolean isSubnetIp, WriteTransaction writeConfigTxn) {
         if (vpnId == null || port == null) {
             return;
         }
@@ -699,7 +763,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NeutronvpnUtils.buildVpnInterfaceIdentifier(infName);
 
         try {
-            WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
             isLockAcquired = NeutronvpnUtils.lock(infName);
             Optional<VpnInterface> optionalVpnInterface = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType
                     .CONFIGURATION, vpnIfIdentifier);
@@ -742,7 +805,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
                 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier, vpnIfBuilder
                         .build());
-                writeConfigTxn.submit();
             } else {
                 LOG.error("VPN Interface {} not found", infName);
             }
@@ -864,15 +926,6 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 l3vni = vpn.getL3vni();
             }
 
-            if (vpn.getRouteDistinguisher().size() > 1) {
-                msg = String.format("Creation of VPN failed for VPN %s due to multiple RD input %s",
-                        vpn.getId().getValue(), vpn.getRouteDistinguisher());
-                LOG.warn(msg);
-                error = RpcResultBuilder.newWarning(ErrorType.PROTOCOL, "invalid-input", msg);
-                errorList.add(error);
-                warningcount++;
-                continue;
-            }
             List<String> existingRDs = NeutronvpnUtils.getExistingRDs(dataBroker);
             if (existingRDs.contains(vpn.getRouteDistinguisher().get(0))) {
                 msg = String.format("Creation of L3VPN failed for VPN %s as another VPN with the same RD %s "
@@ -1153,6 +1206,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
 
         final Uuid routerId = NeutronvpnUtils.getVpnMap(dataBroker, vpnId).getRouterId();
+        final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
+        if (isVpnOfTypeL2(vpnInstance)) {
+            neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
+                    NeutronEvpnUtils.Operation.ADD);
+        }
         // Check if there are ports on this subnet and add corresponding
         // vpn-interfaces
         List<Uuid> portList = sn.getPortList();
@@ -1172,43 +1230,45 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected void updateVpnForSubnet(Uuid vpnId, Uuid subnet, boolean isBeingAssociated) {
-        LOG.debug("Updating VPN {} for subnet {}", vpnId.getValue(), subnet.getValue());
-        // Read the subnet first to see if its already associated to a VPN
-        Uuid oldVpnId = null;
-        InstanceIdentifier<Subnetmap> snId = InstanceIdentifier.builder(Subnetmaps.class)
-            .child(Subnetmap.class, new SubnetmapKey(subnet)).build();
-        Subnetmap sn = null;
-        Optional<Subnetmap> optSn = NeutronvpnUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION, snId);
-        if (optSn.isPresent()) {
-            sn = optSn.get();
-            oldVpnId = sn.getVpnId();
-            List<String> ips = sn.getRouterInterfaceFixedIps();
-            for (String ipValue : ips) {
-                // Update the association of router-interface to external vpn
-                String portName =
-                    NeutronvpnUtils.getNeutronPortNameFromVpnPortFixedIp(dataBroker, oldVpnId.getValue(), ipValue);
-                if (portName != null) {
-                    updateVpnInterface(vpnId, oldVpnId,
-                        NeutronvpnUtils.getNeutronPort(dataBroker, new Uuid(portName)),
-                        isBeingAssociated, true);
-                }
-            }
-        }
-        sn = updateSubnetNode(subnet, null, vpnId);
+    private void updateVpnForSubnet(Uuid oldVpnId, Uuid newVpnId, Uuid subnet, boolean isBeingAssociated) {
+        LOG.debug("Moving subnet {} from oldVpn {} to newVpn {} ", subnet.getValue(),
+                oldVpnId.getValue(), newVpnId.getValue());
+        Subnetmap sn = updateSubnetNode(subnet, null, newVpnId);
         if (sn == null) {
-            LOG.error("subnetmap is null, cannot update VPN {} for subnet {}", vpnId.getValue(), subnet.getValue());
+            LOG.error("Updating subnet {} with newVpn {} failed", subnet.getValue(), newVpnId.getValue());
+            return;
+        }
+
+        //Update Router Interface first synchronously.
+        //CAUTION:  Please DONOT make the router interface VPN Movement as an asynchronous commit again !
+        try {
+            WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
+            updateVpnInterface(newVpnId, oldVpnId,
+                    NeutronvpnUtils.getNeutronPort(dataBroker, sn.getRouterInterfacePortId()),
+                    isBeingAssociated, true, wrtConfigTxn);
+            wrtConfigTxn.submit().checkedGet();
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("Failed to update router interface {} in subnet {} from oldVpnId {} to newVpnId {}, returning",
+                    sn.getRouterInterfacePortId().getValue(), subnet.getValue(), oldVpnId, newVpnId);
             return;
         }
+
         // Check for ports on this subnet and update association of
         // corresponding vpn-interfaces to external vpn
         List<Uuid> portList = sn.getPortList();
         if (portList != null) {
-            for (Uuid port : sn.getPortList()) {
+            for (Uuid port : portList) {
                 LOG.debug("Updating vpn-interface for port {} isBeingAssociated {}",
                     port.getValue(), isBeingAssociated);
-                updateVpnInterface(vpnId, oldVpnId, NeutronvpnUtils.getNeutronPort(dataBroker, port),
-                        isBeingAssociated, false);
+                final DataStoreJobCoordinator portDataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+                portDataStoreCoordinator.enqueueJob("PORT-" + port.getValue(), () -> {
+                    WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
+                    List<ListenableFuture<Void>> futures = new ArrayList<>();
+                    updateVpnInterface(newVpnId, oldVpnId, NeutronvpnUtils.getNeutronPort(dataBroker, port),
+                            isBeingAssociated, false, wrtConfigTxn);
+                    futures.add(wrtConfigTxn.submit());
+                    return futures;
+                });
             }
         }
     }
@@ -1493,7 +1553,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
-    protected void removeVpn(Uuid id) {
+    public void removeVpn(Uuid id) {
         // read VPNMaps
         VpnMap vpnMap = NeutronvpnUtils.getVpnMap(dataBroker, id);
         Uuid router = (vpnMap != null) ? vpnMap.getRouterId() : null;
@@ -1523,6 +1583,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
         final Uuid routerId = vpnMap.getRouterId();
         Subnetmap sn = NeutronvpnUtils.getSubnetmap(dataBroker, subnet);
+        final VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpnId.getValue());
+        if (isVpnOfTypeL2(vpnInstance)) {
+            neutronEvpnUtils.updateElanAndVpn(vpnInstance, sn.getNetworkId().getValue(),
+                    NeutronEvpnUtils.Operation.DELETE);
+        }
         if (sn != null) {
             // Check if there are ports on this subnet; remove corresponding vpn-interfaces
             List<Uuid> portList = sn.getPortList();
@@ -1552,6 +1617,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         }
     }
 
+    private boolean isVpnOfTypeL2(VpnInstance vpnInstance) {
+        return vpnInstance != null && vpnInstance.getType() == VpnInstance.Type.L2;
+    }
+
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     protected void associateRouterToVpn(Uuid vpnId, Uuid routerId) {
@@ -1560,7 +1629,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         List<Uuid> routerSubnets = NeutronvpnUtils.getNeutronRouterSubnetIds(dataBroker, routerId);
         if (routerSubnets != null) {
             for (Uuid subnetId : routerSubnets) {
-                updateVpnForSubnet(vpnId, subnetId, true);
+                updateVpnForSubnet(routerId, vpnId, subnetId, true);
             }
         }
         try {
@@ -1589,7 +1658,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         if (routerSubnets != null) {
             for (Uuid subnetId : routerSubnets) {
                 LOG.debug("Updating association of subnets to internal vpn {}", routerId.getValue());
-                updateVpnForSubnet(routerId, subnetId, false);
+                updateVpnForSubnet(vpnId, routerId, subnetId, false);
             }
         }
         clearFromVpnMaps(vpnId, routerId, null);
@@ -1607,6 +1676,13 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         List<String> failedNwList = new ArrayList<>();
         List<Uuid> passedNwList = new ArrayList<>();
         if (!networks.isEmpty()) {
+            VpnInstance vpnInstance = VpnHelper.getVpnInstance(dataBroker, vpn.getValue());
+            if (vpnInstance == null) {
+                LOG.error("VPN %s not present when associating network to it", vpn.getValue());
+                failedNwList.add(String.format("Failed to associate network on vpn %s as vpn is not present",
+                        vpn.getValue()));
+                return failedNwList;
+            }
             // process corresponding subnets for VPN
             for (Uuid nw : networks) {
                 Network network = NeutronvpnUtils.getNeutronNetwork(dataBroker, nw);
@@ -1624,6 +1700,10 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 } else if (vpnId != null) {
                     failedNwList.add(String.format("network %s already associated to another VPN %s", nw.getValue(),
                             vpnId.getValue()));
+                } else if (isVpnOfTypeL2(vpnInstance)
+                        && (neutronEvpnUtils.isVpnAssociatedWithNetwork(vpnInstance))) {
+                    LOG.error("EVPN supports only one network to be associated");
+                    failedNwList.add(String.format("EVPN supports only one network to be associated"));
                 } else {
                     List<Uuid> networkSubnets = NeutronvpnUtils.getSubnetIdsFromNetworkId(dataBroker, nw);
                     LOG.debug("Adding network subnets...{}", networkSubnets);
@@ -2191,7 +2271,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         VpnInterfaceBuilder vpnb = new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(infName))
                 .setName(infName)
                 .setVpnInstanceName(vpnId.getValue())
-                .setIsRouterInterface(isRouterInterface);
+                .setRouterInterface(isRouterInterface);
         if (adjacencies != null) {
             vpnb.addAugmentation(Adjacencies.class, adjacencies);
         }
@@ -2233,4 +2313,19 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
         floatingIpMapListener.dissociatefixedIPFromFloatingIP(fixedNeutronPortName);
     }
+
+    @Override
+    public Future<RpcResult<CreateEVPNOutput>> createEVPN(CreateEVPNInput input) {
+        return neutronEvpnManager.createEVPN(input);
+    }
+
+    @Override
+    public Future<RpcResult<GetEVPNOutput>> getEVPN(GetEVPNInput input) {
+        return neutronEvpnManager.getEVPN(input);
+    }
+
+    @Override
+    public Future<RpcResult<DeleteEVPNOutput>> deleteEVPN(DeleteEVPNInput input) {
+        return neutronEvpnManager.deleteEVPN(input);
+    }
 }