Create l3vpn & asso with ext-nw failed 62/91762/5
authorKarthikeyan Krishnan <karthikeyangceb007@gmail.com>
Wed, 29 Jul 2020 16:01:31 +0000 (21:31 +0530)
committerKarthikeyan Krishnan <karthikeyangceb007@gmail.com>
Tue, 4 Aug 2020 12:54:31 +0000 (18:24 +0530)
Issue:
=======
Creation of SNAT use case via REST API fails creating vpn
(Creation and Association to VPN in Single REST API Call)

Using Jumbo RPC Call to create the internet BGP-VPN instance(l3vpn)
and at the same request call associate the external GRE provider network
also in a single REST API call is FAILED due to absence of vpn-instance
OPERATIONAL data store.

Solution:
==========
NeutronVPN YANG model has redesigned properly to work internet VPN
use case for both V4 and V6 networks.

"vpn-instance-op-data" should be created/updated/removed
by VPN Module only. Since it is VPN drivern OPERATIONAL data store.

Have modified the NeutronVPN design to just remove the
"vpn-instance-op-data" from NeutronVPN module to VPN Module.

"vpn-instance-op-data" is populated based on the CONFIG vpn-instance
data.

Signed-off-by: Karthikeyan Krishnan <karthikeyangceb007@gmail.com>
Change-Id: I6ff3e54c3302eb0ee3c6f238dc27f2567ca5f72a

neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnManager.java
neutronvpn/impl/src/main/java/org/opendaylight/netvirt/neutronvpn/NeutronvpnUtils.java
vpnmanager/api/src/main/yang/odl-l3vpn.yang
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInstanceListener.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java

index dc9fdfb46c8d88567f9dc7b204b8347e184a04c6..b44bef074ad84cc8e000fe5bf66e8f61d6f5e6a0 100644 (file)
@@ -33,6 +33,7 @@ import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -72,7 +73,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
 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;
@@ -587,7 +587,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             LOG.debug("updating existing vpninstance node");
         } else {
             builder = new VpnInstanceBuilder().withKey(new VpnInstanceKey(vpnName)).setVpnInstanceName(vpnName)
-                    .setL2vpn(isL2Vpn).setL3vni(l3vni);
+                    .setL2vpn(isL2Vpn).setL3vni(l3vni).setBgpvpnType(VpnInstance.BgpvpnType.InternalVPN);
         }
         if (irt != null && !irt.isEmpty()) {
             if (ert != null && !ert.isEmpty()) {
@@ -622,7 +622,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
 
         VpnTargets vpnTargets = new VpnTargetsBuilder().setVpnTarget(vpnTargetList).build();
         if (rd != null && !rd.isEmpty()) {
-            builder.setRouteDistinguisher(rd).setVpnTargets(vpnTargets);
+            builder.setRouteDistinguisher(rd).setVpnTargets(vpnTargets).setBgpvpnType(VpnInstance.BgpvpnType.BGPVPN);
         }
 
         builder.setIpAddressFamilyConfigured(VpnInstance.IpAddressFamilyConfigured.forValue(ipVersion.choice));
@@ -2358,7 +2358,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             }
         }
         if (ipVersion != IpVersionChoice.UNDEFINED) {
-            LOG.debug("associateRouterToVpn: Updating vpnInstanceOpDataEntrywith ip address family {} for VPN {} ",
+            LOG.debug("associateRouterToVpn: Updating vpnInstance ip address family {} for VPN {} ",
                     ipVersion, vpnId);
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
         }
@@ -2399,7 +2399,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
             updateVpnForSubnet(vpnId, routerId, sn.getId(), false);
         }
         if (ipVersion != IpVersionChoice.UNDEFINED) {
-            LOG.debug("dissociateRouterFromVpn; Updating vpnInstanceOpDataEntry with ip address family {} for VPN {} ",
+            LOG.debug("dissociateRouterFromVpn; Updating vpnInstance with ip address family {} for VPN {} ",
                     ipVersion, vpnId);
             neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion,
                     false);
@@ -2417,6 +2417,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected List<String> associateNetworksToVpn(@NonNull Uuid vpnId, @NonNull List<Uuid> networkList) {
         List<String> failedNwList = new ArrayList<>();
         HashSet<Uuid> passedNwList = new HashSet<>();
+        ConcurrentMap<Uuid, Network> extNwMap = new ConcurrentHashMap<>();
         boolean isExternalNetwork = false;
         if (networkList.isEmpty()) {
             LOG.error("associateNetworksToVpn: Failed as given networks list is empty, VPN Id: {}", vpnId.getValue());
@@ -2440,6 +2441,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 return failedNwList;
             }
             Set<VpnTarget> routeTargets = vpnManager.getRtListForVpn(vpnId.getValue());
+            boolean isIpFamilyUpdated = false;
             for (Uuid nw : networkList) {
                 Network network = neutronvpnUtils.getNeutronNetwork(nw);
                 if (network == null) {
@@ -2464,12 +2466,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                                    + "another VPN %s", nw.getValue(), networkVpnId.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;
+                /* Handle association of external network(s) to Internet BGP-VPN use case outside of the
+                 * networkList iteration
+                 */
+                if (neutronvpnUtils.getIsExternal(network)) {
+                    extNwMap.put(nw, network);
                 }
                 if (NeutronvpnUtils.getIsExternal(network)) {
                     isExternalNetwork = true;
@@ -2489,10 +2490,12 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                         ipVersion = ipVersion.addVersion(ipVers);
                     }
                 }
-                if (ipVersion != IpVersionChoice.UNDEFINED) {
-                    LOG.debug("associateNetworksToVpn: Updating vpnInstanceOpDataEntry with ip address family {}"
+                //Update vpnInstance for IP address family
+                if (ipVersion != IpVersionChoice.UNDEFINED && !isIpFamilyUpdated) {
+                    LOG.debug("associateNetworksToVpn: Updating vpnInstance with ip address family {}"
                             + " for VPN {} ", ipVersion, vpnId);
                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
+                    isIpFamilyUpdated = true;
                 }
                 for (Subnetmap subnetmap : subnetmapList) {
                     Uuid subnetId = subnetmap.getId();
@@ -2514,6 +2517,18 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                     }
                 }
                 passedNwList.add(nw);
+                //Handle association of external network(s) to Internet BGP-VPN Instance use case
+                if (!extNwMap.isEmpty() || extNwMap != null) {
+                    for (Network extNw : extNwMap.values()) {
+                        if (!associateExtNetworkToVpn(vpnId, extNw, vpnInstance.getBgpvpnType())) {
+                            LOG.error("associateNetworksToVpn: Failed to associate Provider External Network {} with "
+                                    + "VPN {}", extNw, vpnId.getValue());
+                            failedNwList.add(String.format("Failed to associate Provider External Network %s with "
+                                            + "VPN %s", extNw, vpnId.getValue()));
+                            continue;
+                        }
+                    }
+                }
             }
         } catch (ExecutionException | InterruptedException e) {
             LOG.error("associateNetworksToVpn: Failed to associate VPN {} with networks {}: ", vpnId.getValue(),
@@ -2529,18 +2544,17 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
         return failedNwList;
     }
 
-    private boolean associateExtNetworkToVpn(@NonNull Uuid vpnId, @NonNull Network extNet) {
+    private boolean associateExtNetworkToVpn(@NonNull Uuid vpnId, @NonNull Network extNet,
+                                             VpnInstance.BgpvpnType bgpVpnType) {
         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 (!vpnOpDataEntry.getBgpvpnType().equals(BgpvpnType.BGPVPNInternet)) {
-            LOG.info("associateExtNetworkToVpn: set type {} for VPN {}", BgpvpnType.BGPVPNInternet, vpnId.getValue());
-            neutronvpnUtils.updateVpnInstanceOpWithType(BgpvpnType.BGPVPNInternet, vpnId);
+        if (!bgpVpnType.equals(VpnInstance.BgpvpnType.InternetBGPVPN)) {
+            LOG.info("associateExtNetworkToVpn: External network {} is associated to VPN {}."
+                            + "Hence set vpnInstance type to {} from {} ", extNet.key().getUuid().getValue(),
+                    vpnId.getValue(), VpnInstance.BgpvpnType.InternetBGPVPN.getName(),
+                    VpnInstance.BgpvpnType.BGPVPN.getName());
+            neutronvpnUtils.updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType.InternetBGPVPN, vpnId);
         }
         //Update VpnMap with ext-nw is needed first before processing V6 internet default fallback flows
         List<Uuid> extNwList = Collections.singletonList(extNet.key().getUuid());
@@ -2582,6 +2596,7 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
     protected List<String> dissociateNetworksFromVpn(@NonNull Uuid vpnId, @NonNull List<Uuid> networkList) {
         List<String> failedNwList = new ArrayList<>();
         HashSet<Uuid> passedNwList = new HashSet<>();
+        ConcurrentMap<Uuid, Network> extNwMap = new ConcurrentHashMap<>();
         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",
@@ -2616,16 +2631,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                                 vpnId.getValue()));
                 continue;
             }
-            if (NeutronvpnUtils.getIsExternal(network)) {
-                if (disassociateExtNetworkFromVpn(vpnId, network)) {
-                    passedNwList.add(nw);
-                } else {
-                    LOG.error("dissociateNetworksFromVpn: Failed to withdraw Provider Network {} from VPN {}",
-                              nw.getValue(), vpnId.getValue());
-                    failedNwList.add(String.format("Failed to withdraw Provider Network %s from VPN %s", nw.getValue(),
-                                                   vpnId.getValue()));
-                    continue;
-                }
+            /* Handle disassociation of external network(s) from Internet BGP-VPN use case outside of the
+             * networkList iteration
+             */
+            if (neutronvpnUtils.getIsExternal(network)) {
+                extNwMap.put(nw, network);
             }
             IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
             for (Uuid subnet : networkSubnets) {
@@ -2653,11 +2663,25 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
             }
             if (ipVersion != IpVersionChoice.UNDEFINED) {
-                LOG.debug("dissociateNetworksFromVpn: Updating vpnInstanceOpDataEntryupdate with ip address family {}"
+                LOG.debug("dissociateNetworksFromVpn: Updating vpnInstance with ip address family {}"
                         + " for VPN {}", ipVersion, vpnId);
                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
             }
         }
+        //Handle disassociation of external network(s) from Internet BGP-VPN Instance use case
+        if (!extNwMap.isEmpty() || extNwMap != null) {
+            for (Network extNw : extNwMap.values()) {
+                if (disassociateExtNetworkFromVpn(vpnId, extNw)) {
+                    passedNwList.add(extNw.getUuid());
+                } else {
+                    LOG.error("dissociateNetworksFromVpn: Failed to withdraw External Provider Network {} from VPN {}",
+                            extNw, vpnId.getValue());
+                    failedNwList.add(String.format("Failed to withdraw External Provider Network %s from VPN %s",
+                            extNw, vpnId.getValue()));
+                    continue;
+                }
+            }
+        }
         clearFromVpnMaps(vpnId, null, new ArrayList<>(passedNwList));
         LOG.info("dissociateNetworksFromVpn: Network(s) {} disassociated from L3VPN {} successfully",
                 passedNwList, vpnId.getValue());
@@ -2681,10 +2705,11 @@ public class NeutronvpnManager implements NeutronvpnService, AutoCloseable, Even
                 }
             }
         }
-        //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);
+        ///Set VPN Type is BGPVPN from InternetBGPVPN
+        LOG.info("disassociateExtNetworkFromVpn: Set BGP-VPN type with {} for VPN {} and update IPv6 address family. "
+                        + "Since external network is disassociated from VPN {}",
+                VpnInstance.BgpvpnType.BGPVPN, extNet, vpnId.getValue());
+        neutronvpnUtils.updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType.BGPVPN, vpnId);
         IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
         for (Uuid snId : neutronvpnUtils.getPrivateSubnetsToExport(extNet, vpnId)) {
             Subnetmap sm = neutronvpnUtils.getSubnetmap(snId);
index d54bda3285e3300444c1986975f14d51367c9319..9b7411e1fed0716a38471c6a223c3405523fe861 100644 (file)
@@ -8,7 +8,6 @@
 package org.opendaylight.netvirt.neutronvpn;
 
 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
-import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableBiMap;
@@ -94,7 +93,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neu
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnListKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
 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.VpnInstanceOpDataEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalSubnets;
@@ -1670,34 +1668,28 @@ public class NeutronvpnUtils {
         }
     }
 
-    public void updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType choice, @NonNull Uuid vpn) {
-        String primaryRd = getVpnRd(vpn.getValue());
-        if (primaryRd == null) {
-            LOG.debug("updateVpnInstanceOpWithType: Update BgpvpnType {} for {}."
-                    + "Primary RD not found", choice, vpn.getValue());
-            return;
-        }
-        InstanceIdentifier<VpnInstanceOpDataEntry> id = getVpnOpDataIdentifier(primaryRd);
-
-        Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
-            read(LogicalDatastoreType.OPERATIONAL, id);
-        if (!vpnInstanceOpDataEntryOptional.isPresent()) {
-            LOG.debug("updateVpnInstanceOpWithType: Update BgpvpnType {} for {}."
-                    + "VpnInstanceOpDataEntry not found", choice, vpn.getValue());
-            return;
-        }
-        VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnInstanceOpDataEntryOptional.get();
-        if (vpnInstanceOpDataEntry.getBgpvpnType().equals(choice)) {
-            LOG.debug("updateVpnInstanceOpWithType: Update BgpvpnType {} for {}."
-                    + "VpnInstanceOpDataEntry already set", choice, vpn.getValue());
-            return;
-        }
-        VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder(vpnInstanceOpDataEntry);
-        builder.setBgpvpnType(choice);
-        LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
-            tx.merge(id, builder.build());
-            LOG.debug("updateVpnInstanceOpWithType: sent merge to operDS BgpvpnType {} for {}", choice, vpn.getValue());
-        }), LOG, "Error updating VPN instance op {} with type {}", vpn, choice);
+    public void updateVpnInstanceWithBgpVpnType(VpnInstance.BgpvpnType bgpvpnType, @NonNull Uuid vpnName) {
+        jobCoordinator.enqueueJob("VPN-" + vpnName.getValue(), () -> {
+            VpnInstance vpnInstance = getVpnInstance(dataBroker, vpnName);
+            if (vpnInstance == null) {
+                LOG.error("updateVpnInstanceWithBgpVpnType: Failed to Update VpnInstance {} with BGP-VPN type {}."
+                        + "VpnInstance is does not exist in the CONFIG. Do nothing.", vpnName.getValue(), bgpvpnType);
+                return Collections.emptyList();
+            }
+            if (vpnInstance.isL2vpn()) {
+                LOG.error("updateVpnInstanceWithBgpVpnType: Failed to Update VpnInstance {} with BGP-VPN type {}."
+                        + "VpnInstance is L2 instance. Do nothing.", vpnName.getValue(), bgpvpnType);
+                return Collections.emptyList();
+            }
+            VpnInstanceBuilder builder = new VpnInstanceBuilder(vpnInstance);
+            builder.setBgpvpnType(bgpvpnType);
+            InstanceIdentifier<VpnInstance> vpnIdentifier = InstanceIdentifier.builder(VpnInstances.class)
+                    .child(VpnInstance.class, new VpnInstanceKey(vpnName.getValue())).build();
+            LOG.info("updateVpnInstanceWithBgpVpnType: Successfully updated the VpnInstance {} with BGP-VPN type {}",
+                    vpnName.getValue(), bgpvpnType);
+            return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
+                    CONFIGURATION, tx -> tx.merge(vpnIdentifier, builder.build())));
+        });
     }
 
     public static RouterIds getvpnInstanceRouterIds(Uuid routerId) {
index ef1af3baeb270a189760bdd89acd3991f44e87b2..2b1dea746147f5b3ddd83b60c07ad060e5e14b64 100644 (file)
@@ -292,17 +292,17 @@ module odl-l3vpn {
            }
            leaf bgpvpn-type {
               type enumeration {
-                 enum BGPVPNInternet {
+                 enum InternetBGPVPN {
                     value "0";
-                    description "BGPVPN Internet";
+                    description "Internet BGPVPN";
                  }
-                 enum BGPVPNExternal {
+                 enum BGPVPN {
                     value "1";
-                    description "BGPVPN External";
+                    description "BGPVPN";
                  }
-                 enum VPN {
+                 enum InternalVPN {
                     value "2";
-                    description "Default VPN";
+                    description "InternalVPN";
                  }
               }
            }
index a77c0c9a8647464e4a14e9759c9babac36150fd3..adc4752ccc1d002b3dc1976cade0fca36266e6c9 100644 (file)
@@ -17,9 +17,11 @@ import com.google.common.util.concurrent.MoreExecutors;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -51,9 +53,12 @@ import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.infrautils.utils.concurrent.Executors;
 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
 import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
+import org.opendaylight.yang.gen.v1.urn.ericsson.params.xml.ns.yang.ebgp.rev150901.AddressFamily;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ExternalTunnelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
@@ -61,6 +66,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.ext
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.DcGatewayIpList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIp;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.dc.gateway.ip.list.DcGatewayIpKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIds;
 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.VpnInstanceOpDataEntryBuilder;
@@ -88,6 +94,7 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
     private final IdManagerService idManager;
     private final VpnInterfaceManager vpnInterfaceManager;
     private final IFibManager fibManager;
+    private final IBgpManager bgpManager;
     private final VpnOpDataSyncer vpnOpDataNotifier;
     private final IMdsalApiManager mdsalManager;
     private final JobCoordinator jobCoordinator;
@@ -96,7 +103,7 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
     @Inject
     public VpnInstanceListener(final DataBroker dataBroker, final IdManagerService idManager,
             final VpnInterfaceManager vpnInterfaceManager, final IFibManager fibManager,
-            final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager,
+            final IBgpManager bgpManager, final VpnOpDataSyncer vpnOpDataSyncer, final IMdsalApiManager mdsalManager,
             final JobCoordinator jobCoordinator, VpnUtil vpnUtil) {
         super(dataBroker, LogicalDatastoreType.CONFIGURATION,
                 InstanceIdentifier.create(VpnInstances.class).child(VpnInstance.class),
@@ -106,6 +113,7 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
         this.idManager = idManager;
         this.vpnInterfaceManager = vpnInterfaceManager;
         this.fibManager = fibManager;
+        this.bgpManager = bgpManager;
         this.vpnOpDataNotifier = vpnOpDataSyncer;
         this.mdsalManager = mdsalManager;
         this.jobCoordinator = jobCoordinator;
@@ -176,17 +184,179 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
     public void update(InstanceIdentifier<VpnInstance> identifier,
         VpnInstance original, VpnInstance update) {
         LOG.trace("VPN-UPDATE: update: VPN event key: {}, value: {}.", identifier, update);
-        String vpnName = update.getVpnInstanceName();
-        if (original != null && update != null
-                && original.getRouteDistinguisher() != null
-                && update.getRouteDistinguisher() != null
-                && original.getRouteDistinguisher().size()
-                !=  update.getRouteDistinguisher().size()) {
-            LOG.debug("VPN-UPDATE: VpnInstance:{} updated with new RDs: {} from old RDs: {}", vpnName,
-                    update.getRouteDistinguisher(),  original.getRouteDistinguisher());
-            vpnUtil.updateVpnInstanceWithRdList(vpnName, update.getRouteDistinguisher());
+        if (Objects.equals(original, update)) {
+            return;
+        }
+        jobCoordinator.enqueueJob("VPN-" + original.getVpnInstanceName(),
+                new UpdateVpnInstanceWorker(dataBroker, identifier, original, update));
+    }
+
+    private class UpdateVpnInstanceWorker implements Callable<List<? extends ListenableFuture<?>>> {
+        private final Logger log = LoggerFactory.getLogger(VpnInstanceListener.UpdateVpnInstanceWorker.class);
+        VpnInstance original;
+        VpnInstance update;
+        InstanceIdentifier<VpnInstance> vpnIdentifier;
+        DataBroker broker;
+        String vpnName;
+
+        UpdateVpnInstanceWorker(DataBroker broker,
+                                InstanceIdentifier<VpnInstance> identifier,
+                                VpnInstance original,
+                                VpnInstance update) {
+            this.broker = broker;
+            this.vpnIdentifier = identifier;
+            this.original = original;
+            this.update = update;
+            this.vpnName = update.getVpnInstanceName();
+        }
+
+        @Override
+        @SuppressWarnings("checkstyle:ForbidCertainMethod")
+        public List<ListenableFuture<Void>> call() {
+            WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
+            List<ListenableFuture<Void>> futures = new ArrayList<>();
+            String primaryRd = vpnUtil.getVpnRd(vpnName);
+            if (primaryRd == null) {
+                log.error("{}, failed to update VPN: PrimaryRD is null for vpnName {}", LOGGING_PREFIX_UPDATE, vpnName);
+                return futures;
+            }
+            updateVpnInstance(writeOperTxn, primaryRd);
+            try {
+                writeOperTxn.commit().get();
+            } catch (InterruptedException | ExecutionException e) {
+                log.error("{}, failed to update VPN: Exception in updating vpn {} rd {} ", LOGGING_PREFIX_UPDATE,
+                        vpnName, update.getRouteDistinguisher(), e);
+                futures.add(Futures.immediateFailedFuture(e));
+                return futures;
+            }
+            ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
+            boolean isIpAddressFamilyUpdated = false;
+            if (original.getIpAddressFamilyConfigured() == VpnInstance.IpAddressFamilyConfigured.Undefined
+                    && update.getIpAddressFamilyConfigured() != original.getIpAddressFamilyConfigured()) {
+                isIpAddressFamilyUpdated = true;
+            }
+            Futures.addCallback(listenableFuture,
+                    new PostVpnInstanceChangeWorker(update , isIpAddressFamilyUpdated, primaryRd),
+                    MoreExecutors.directExecutor());
+            return futures;
+        }
+
+        private class PostVpnInstanceChangeWorker implements FutureCallback<List<Void>> {
+            private final Logger log = LoggerFactory.getLogger(PostVpnInstanceChangeWorker.class);
+            VpnInstance vpnInstance;
+            String vpnName;
+            boolean isIpAddressFamilyUpdated;
+            String primaryRd;
+
+            PostVpnInstanceChangeWorker(VpnInstance vpnInstance, boolean isIpAddressFamilyUpdated, String primaryRd) {
+                this.vpnInstance = vpnInstance;
+                this.vpnName = vpnInstance.getVpnInstanceName();
+                this.isIpAddressFamilyUpdated = isIpAddressFamilyUpdated;
+                this.primaryRd = primaryRd;
+            }
+
+            /**
+             * This implies that all the future instances have returned success. -- TODO: Confirm this
+             */
+            @Override
+            public void onSuccess(List<Void> voids) {
+                if (!VpnUtil.isBgpVpn(vpnName, primaryRd)) {
+                    // plain router
+                    notifyTask();
+                    vpnInterfaceManager.vpnInstanceIsReady(vpnName);
+                    return;
+                }
+                if (isIpAddressFamilyUpdated) {
+                    //bgpvpn
+                    notifyTask();
+                    vpnInterfaceManager.vpnInstanceIsReady(vpnName);
+                }
+            }
+
+            /**
+             * This method is used to handle failure callbacks.
+             * If more retry needed, the retrycount is decremented and mainworker is executed again.
+             * After retries completed, rollbackworker is executed.
+             * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
+             */
+
+            @Override
+            public void onFailure(Throwable throwable) {
+                log.error("{} onFailure: Job for vpnInstance: {} with rd {} failed with exception:", LOGGING_PREFIX_ADD,
+                        vpnName, primaryRd, throwable);
+                vpnInterfaceManager.vpnInstanceFailed(vpnName);
+            }
+
+            private void notifyTask() {
+                vpnOpDataNotifier.notifyVpnOpDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId,
+                        vpnInstance.getVpnInstanceName());
+                vpnOpDataNotifier.notifyVpnOpDataReady(VpnOpDataSyncer.VpnOpDataType.vpnOpData,
+                        vpnInstance.getVpnInstanceName());
+            }
+        }
+
+        public void updateVpnInstance(WriteTransaction writeOperTxn, String primaryRd) {
+            log.trace("updateVpnInstance: VPN event key: {}, value: {}.", vpnIdentifier, update);
+            InstanceIdentifier<VrfTables> id = VpnUtil.buildVrfTableForPrimaryRd(primaryRd);
+            Optional<VrfTables> vrfTable;
+            try {
+                vrfTable = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                        LogicalDatastoreType.CONFIGURATION, id);
+            } catch (ExecutionException | InterruptedException e) {
+                log.trace("updateVpnInstance: Exception while reading FIB VRF Table for VPN Instance {} with "
+                        + "Primary RD {}.", vpnName, primaryRd);
+                return;
+            }
+            //TODO Later if FIB VRF table is available we need to callback the vpnInstanceOpData Update to proceed
+            if (!vrfTable.isPresent()) {
+                log.error("updateVpnInstance: FIB VRF table is not present for the VPN Instance {} "
+                                + "with Primary RD {}. Unable to Proceed VpnInstanceOpData Update event {}",
+                        vpnName, primaryRd, update);
+                return;
+            }
+            List<String> vpnInstanceUpdatedRdList = Collections.emptyList();
+            boolean isBgpVrfTableUpdateRequired = false;
+            boolean isVpnInstanceRdUpdated = false;
+            //Handle VpnInstance Address Family update
+            int originalIpAddrFamilyValue = original.getIpAddressFamilyConfigured().getIntValue();
+            int updateIpAddrFamilyValue = update.getIpAddressFamilyConfigured().getIntValue();
+            if (originalIpAddrFamilyValue != updateIpAddrFamilyValue) {
+                log.debug("updateVpnInstance: VpnInstance: {} updated with IP address family {} from IP address "
+                                + "family {}", vpnName, update.getIpAddressFamilyConfigured().getName(),
+                        original.getIpAddressFamilyConfigured().getName());
+                vpnUtil.setVpnInstanceOpDataWithAddressFamily(vpnName, update.getIpAddressFamilyConfigured(),
+                        writeOperTxn);
+            }
+            //Update VpnInstanceOpData with BGPVPN to Internet BGPVPN and vice-versa
+            if (original.getBgpvpnType() != update.getBgpvpnType()) {
+                log.debug("updateVpnInstance: VpnInstance: {} updated with BGP-VPN type: {} from BGP-VPN type: {}",
+                        vpnName, update.getBgpvpnType(), original.getBgpvpnType());
+                vpnUtil.updateVpnInstanceOpDataWithVpnType(vpnName, update.getBgpvpnType(), writeOperTxn);
+            }
+            //Handle BGP-VPN Instance RD Update
+            if ((update.getBgpvpnType() != VpnInstance.BgpvpnType.InternalVPN)) {
+                if (originalIpAddrFamilyValue < updateIpAddrFamilyValue) {
+                    isBgpVrfTableUpdateRequired = true;
+                }
+                if (original.getRouteDistinguisher().size() != update.getRouteDistinguisher().size()) {
+                    log.debug("updateVpnInstance: VpnInstance:{} updated with new RDs: {} from old RDs: {}", vpnName,
+                            update.getRouteDistinguisher(), original.getRouteDistinguisher());
+                    vpnUtil.updateVpnInstanceOpDataWithRdList(vpnName, update.getRouteDistinguisher(), writeOperTxn);
+                    /* Update BGP Vrf entry for newly added RD. VPN Instance does not support for
+                     * deleting the existing RDs
+                     */
+                    vpnInstanceUpdatedRdList = update.getRouteDistinguisher() != null
+                            ? new ArrayList<>(update.getRouteDistinguisher()) : new ArrayList<>();
+                    vpnInstanceUpdatedRdList.removeAll(original.getRouteDistinguisher());
+                    isBgpVrfTableUpdateRequired = true;
+                    isVpnInstanceRdUpdated = true;
+                }
+            }
+            //update Bgp VrfTable
+            if (isBgpVrfTableUpdateRequired) {
+                addBgpVrfTableForVpn(update, vpnName, vpnInstanceUpdatedRdList, isVpnInstanceRdUpdated);
+            }
         }
-        vpnInterfaceManager.updateVpnInterfacesForUnProcessAdjancencies(vpnName);
     }
 
     @Override
@@ -289,7 +459,6 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
         if (VpnUtil.isBgpVpn(vpnInstanceName, primaryRd)) {
             List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
                 .instance.op.data.entry.vpntargets.VpnTarget> opVpnTargetList = new ArrayList<>();
-            builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal);
             if (value.getL3vni() != null) {
                 builder.setL3vni(value.getL3vni());
             }
@@ -318,9 +487,9 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
 
             List<String> rds = value.getRouteDistinguisher();
             builder.setRd(rds);
-        } else {
-            builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.VPN);
         }
+        // Get BGP-VPN type configured details from config vpn-instance
+        builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.forValue(value.getBgpvpnType().getIntValue()));
         writeOperTxn.mergeParentStructureMerge(VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd), builder.build());
         LOG.info("{} addVpnInstance: VpnInstanceOpData populated successfully for vpn {} rd {}", LOGGING_PREFIX_ADD,
                 vpnInstanceName, primaryRd);
@@ -504,4 +673,71 @@ public class VpnInstanceListener extends AbstractAsyncDataTreeChangeListener<Vpn
         return VpnConstants.FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
                 + NwConstants.FLOWID_SEPARATOR + vpnName + NwConstants.FLOWID_SEPARATOR + priority;
     }
+
+    @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
+            justification = "https://github.com/spotbugs/spotbugs/issues/811")
+    private void addBgpVrfTableForVpn(VpnInstance vpnInstance, String vpnName, List<String> vpnInstanceUpdatedRdList,
+                                      boolean isVpnInstanceRdUpdated) {
+        String primaryRd = vpnUtil.getPrimaryRd(vpnName);
+        Collection<VpnTarget> vpnTargetCollection = (vpnInstance.getVpnTargets() != null)
+                ? vpnInstance.getVpnTargets().getVpnTarget().values() : null;
+        List<VpnTarget> vpnTargetList = new ArrayList<VpnTarget>(vpnTargetCollection != null ? vpnTargetCollection
+                : Collections.emptyList());
+        List<String> exportRTList = new ArrayList<>();
+        List<String> importRTList = new ArrayList<>();
+        if (!vpnTargetList.isEmpty()) {
+            for (VpnTarget vpnTarget : vpnTargetList) {
+                if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ExportExtcommunity) {
+                    exportRTList.add(vpnTarget.getVrfRTValue());
+                }
+                if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.ImportExtcommunity) {
+                    importRTList.add(vpnTarget.getVrfRTValue());
+                }
+                if (vpnTarget.getVrfRTType() == VpnTarget.VrfRTType.Both) {
+                    exportRTList.add(vpnTarget.getVrfRTValue());
+                    importRTList.add(vpnTarget.getVrfRTValue());
+                }
+            }
+        }
+        synchronized (vpnName.intern()) {
+            List<String> rds = Collections.emptyList();
+            //Vpn Instance RD Update for ECMP use case
+            if (isVpnInstanceRdUpdated) {
+                rds = vpnInstanceUpdatedRdList;
+            } else {
+                rds = vpnInstance.getRouteDistinguisher() != null
+                        ? new ArrayList<>(vpnInstance.getRouteDistinguisher()) : new ArrayList<>();
+            }
+            for (String rd : rds) {
+                List<String> irtList = rd.equals(primaryRd) ? importRTList : Collections.emptyList();
+                int ipAddrFamilyConfigured = vpnInstance.getIpAddressFamilyConfigured().getIntValue();
+                switch (ipAddrFamilyConfigured) {
+                    case 10:
+                        bgpManager.addVrf(rd, irtList, exportRTList, AddressFamily.IPV4);
+                        bgpManager.addVrf(rd, irtList, exportRTList, AddressFamily.IPV6);
+                        LOG.debug("addBgpVrfTableForVpn: ADD BGP VRF table for VPN {} with RD {}, ImportRTList {}, "
+                                + "ExportRTList {} for IPv4andIPv6 AddressFamily ", vpnName, rd, irtList, exportRTList);
+                        break;
+                    case 6:
+                        bgpManager.addVrf(rd, irtList, exportRTList, AddressFamily.IPV6);
+                        LOG.debug("addBgpVrfTableForVpn: ADD BGP VRF table for VPN {} with RD {}, ImportRTList {}, "
+                                + "ExportRTList {} for IPv6 AddressFamily ", vpnName, rd, irtList, exportRTList);
+                        break;
+                    case 4:
+                        bgpManager.addVrf(rd, irtList, exportRTList, AddressFamily.IPV4);
+                        LOG.debug("addBgpVrfTableForVpn: ADD BGP VRF table for VPN {} with RD {}, ImportRTList {}, "
+                                + "ExportRTList {} for IPv4 AddressFamily ", vpnName, rd, irtList, exportRTList);
+                        break;
+                    default:
+                        break;
+                }
+                //L2VPN Use case
+                if (vpnInstance.isL2vpn()) {
+                    bgpManager.addVrf(rd, importRTList, exportRTList, AddressFamily.L2VPN);
+                    LOG.debug("addBgpVrfTableForVpn: ADD BGP VRF table for VPN {} RD {}, ImportRTList {}, "
+                            + "ExportRTList {} for L2VPN AddressFamily ", vpnName, rd, irtList, exportRTList);
+                }
+            }
+        }
+    }
 }
index f703ddc010cc21a60374783ada7787b1ba46a3d0..96ad97f4f3637ed35b9d695cb0d2d3f4bb4795db 100755 (executable)
@@ -784,7 +784,7 @@ public class VpnInterfaceManager extends AbstractAsyncDataTreeChangeListener<Vpn
         for (Adjacency nextHop : nextHopsMap.values()) {
             String rd = primaryRd;
             String nexthopIpValue = nextHop.getIpAddress().split("/")[0];
-            if (vpnInstanceOpData.getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet
+            if (vpnInstanceOpData.getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.InternetBGPVPN
                     && NWUtil.isIpv4Address(nexthopIpValue)) {
                 String prefix = nextHop.getIpAddress() == null ?  "null" :
                       VpnUtil.getIpPrefix(nextHop.getIpAddress());
@@ -1708,7 +1708,7 @@ public class VpnInterfaceManager extends AbstractAsyncDataTreeChangeListener<Vpn
                         String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
                         VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
                         if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
-                                .BgpvpnType.BGPVPNExternal) {
+                                .BgpvpnType.BGPVPN) {
                             externalBgpVpnList.add(newVpnName);
                             break;
                         }
@@ -1725,7 +1725,7 @@ public class VpnInterfaceManager extends AbstractAsyncDataTreeChangeListener<Vpn
                         String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
                         VpnInstanceOpDataEntry vpnInstanceOpDataEntry = vpnUtil.getVpnInstanceOpData(primaryRd);
                         if (vpnInstanceOpDataEntry.getBgpvpnType() == VpnInstanceOpDataEntry
-                                .BgpvpnType.VPN) {
+                                .BgpvpnType.BGPVPN) {
                             routerVpnList.add(newVpnName);
                             break;
                         }
index bce704258b53020985e14dbfa188d46ff0f65447..dcaa1fd0b974df16fe1162777ffb6fe1598208ca 100644 (file)
@@ -1917,8 +1917,7 @@ public final class VpnUtil {
     boolean isBgpVpnInternet(String vpnName) {
         String primaryRd = getVpnRd(vpnName);
         if (primaryRd == null) {
-            LOG.error("isBgpVpnInternet VPN {}."
-                      + "Primary RD not found", vpnName);
+            LOG.error("isBgpVpnInternet VPN {} Primary RD not found", vpnName);
             return false;
         }
         InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
@@ -1930,11 +1929,9 @@ public final class VpnUtil {
                      + "VpnInstanceOpDataEntry not found", vpnName);
             return false;
         }
-        LOG.debug("isBgpVpnInternet VPN {}."
-             + "Successfully VpnInstanceOpDataEntry.getBgpvpnType {}",
+        LOG.debug("isBgpVpnInternet VPN {} Successfully VpnInstanceOpDataEntry.getBgpvpnType {}",
              vpnName, vpnInstanceOpDataEntryOptional.get().getBgpvpnType());
-        if (vpnInstanceOpDataEntryOptional.get().getBgpvpnType() == VpnInstanceOpDataEntry
-               .BgpvpnType.BGPVPNInternet) {
+        if (vpnInstanceOpDataEntryOptional.get().getBgpvpnType() == VpnInstanceOpDataEntry.BgpvpnType.InternetBGPVPN) {
             return true;
         }
         return false;
@@ -2566,4 +2563,94 @@ public final class VpnUtil {
         // FIXME: is there some identifier we can use? LearntVpnVipToPortKey perhaps?
         return JvmGlobalLocks.getLockForString(vpnName + fixedIp);
     }
+
+    public static InstanceIdentifier<VrfTables> buildVrfTableForPrimaryRd(String primaryRd) {
+        InstanceIdentifier.InstanceIdentifierBuilder<VrfTables> idBuilder =
+                InstanceIdentifier.builder(FibEntries.class).child(VrfTables.class, new VrfTablesKey(primaryRd));
+        return idBuilder.build();
+    }
+
+    public void setVpnInstanceOpDataWithAddressFamily(String vpnName,
+                                                      VpnInstance.IpAddressFamilyConfigured ipVersion,
+                                                      WriteTransaction writeOperTxn) {
+        VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpDataEntryFromVpnName(vpnName);
+        if (vpnInstanceOpDataEntry == null) {
+            LOG.error("setVpnInstanceOpDataWithAddressFamily: Unable to set IP address family {} for the "
+                    + "VPN {}. Since VpnInstanceOpData is not yet ready", ipVersion, vpnName);
+            return;
+        }
+        if (vpnInstanceOpDataEntry.getType() == VpnInstanceOpDataEntry.Type.L2) {
+            LOG.error("setVpnInstanceOpDataWithAddressFamily: Unable to set IP address family {} for the "
+                    + "VPN {}. Since VPN type is L2 flavour. Do Nothing.", ipVersion, vpnName);
+            return;
+        }
+        synchronized (vpnName.intern()) {
+            VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder()
+                    .setVrfId(vpnInstanceOpDataEntry.getVrfId());
+            builder.setIpAddressFamilyConfigured(VpnInstanceOpDataEntry.IpAddressFamilyConfigured
+                    .forValue(ipVersion.getIntValue()));
+            InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+                    .child(VpnInstanceOpDataEntry.class,
+                            new VpnInstanceOpDataEntryKey(vpnInstanceOpDataEntry.getVrfId())).build();
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, id, builder.build());
+            LOG.info("setVpnInstanceOpDataWithAddressFamily: Successfully set vpnInstanceOpData with "
+                    + "IP Address family {} for VpnInstance {}", ipVersion.getName(), vpnName);
+        }
+    }
+
+    public void updateVpnInstanceOpDataWithVpnType(String vpnName,
+                                                   VpnInstance.BgpvpnType bgpvpnType,
+                                                   WriteTransaction writeOperTxn) {
+        VpnInstanceOpDataEntry vpnInstanceOpDataEntry = getVpnInstanceOpDataEntryFromVpnName(vpnName);
+        if (vpnInstanceOpDataEntry == null) {
+            LOG.error("updateVpnInstanceOpDataWithVpnType: VpnInstance {} with BGPVPN Type {} update Failed."
+                    + "Since vpnInstanceOpData is not yet ready.", vpnName, bgpvpnType);
+            return;
+        }
+        if (vpnInstanceOpDataEntry.getType() == VpnInstanceOpDataEntry.Type.L2) {
+            LOG.error("updateVpnInstanceOpDataWithVpnType: Unable to update the VpnInstance {} with BGPVPN Type {}."
+                    + "Since VPN type is L2 flavour. Do Nothing.", vpnName, bgpvpnType);
+            return;
+        }
+        synchronized (vpnName.intern()) {
+            VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder()
+                    .setVrfId(vpnInstanceOpDataEntry.getVrfId());
+            builder.setBgpvpnType(VpnInstanceOpDataEntry.BgpvpnType.forValue(bgpvpnType.getIntValue()));
+            InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+                    .child(VpnInstanceOpDataEntry.class,
+                            new VpnInstanceOpDataEntryKey(vpnInstanceOpDataEntry.getVrfId())).build();
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, id, builder.build());
+            LOG.info("updateVpnInstanceOpDataWithVpnType: Successfully updated vpn-instance-op-data with BGPVPN type "
+                    + "{} for the Vpn {}", bgpvpnType, vpnName);
+        }
+    }
+
+    public VpnInstanceOpDataEntry getVpnInstanceOpDataEntryFromVpnName(String vpnName) {
+        String primaryRd = getVpnRd(vpnName);
+        if (primaryRd == null) {
+            LOG.error("getVpnInstanceOpDataEntryFromVpnName: Vpn Instance {} Primary RD not found", vpnName);
+            return null;
+        }
+        return getVpnInstanceOpData(primaryRd);
+    }
+
+    public void updateVpnInstanceOpDataWithRdList(String vpnName, List<String> updatedRdList,
+                                                  WriteTransaction writeOperTxn) {
+        String primaryRd = getVpnRd(vpnName);
+        if (primaryRd == null) {
+            LOG.error("updateVpnInstanceOpDataWithRdList: Unable to get primary RD for the VPN {}. Skip to process "
+                    + "the update RD list {} ", vpnName, updatedRdList);
+            return;
+        }
+        synchronized (vpnName.intern()) {
+            VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd);
+            builder.setRd(updatedRdList);
+            InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+                    .child(VpnInstanceOpDataEntry.class,
+                            new VpnInstanceOpDataEntryKey(primaryRd)).build();
+            writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, id, builder.build());
+            LOG.info("updateVpnInstanceOpDataWithRdList: Successfully updated the VPN {} with list of RDs {}",
+                    vpnName, updatedRdList);
+        }
+    }
 }