NETVIRT-1037: Upstream Fixes --- Review-3
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnUtil.java
index b32274d859fbb251f85daabf8a20f612bc3261a1..8b1f05e101ea0f91e46dc4890a4b86d275b57c87 100755 (executable)
@@ -9,28 +9,35 @@
 package org.opendaylight.netvirt.vpnmanager;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.Iterators;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.math.BigInteger;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
-
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
 import org.opendaylight.genius.mdsalutil.FlowEntity;
 import org.opendaylight.genius.mdsalutil.FlowEntityBuilder;
 import org.opendaylight.genius.mdsalutil.InstructionInfo;
@@ -47,25 +54,29 @@ import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
 import org.opendaylight.genius.utils.ServiceIndex;
 import org.opendaylight.genius.utils.cache.DataStoreCache;
+import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.fibmanager.api.FibHelper;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
+import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
+import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
-import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
 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.instances.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstanceKey;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
-import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceKey;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames.AssociatedSubnetType;
+import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNamesBuilder;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
 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.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
@@ -108,6 +119,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.VpnNexthopsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOpBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.LearntVpnVipToPortData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PrefixToInterface;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.RouterInterfaces;
@@ -115,8 +128,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Sub
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnIdToVpnInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInstanceToVpnId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnInterfaceOpData;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency.AdjacencyType;
 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.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPortBuilder;
@@ -132,10 +147,15 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.rou
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterfaceKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
 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.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnTargets;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpntargets.VpnTarget;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.VpnKey;
@@ -175,6 +195,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.s
 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.SubnetKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.impl.schema.tree.SchemaValidationFailedException;
 import org.slf4j.Logger;
@@ -193,6 +214,13 @@ public final class VpnUtil {
             .child(VpnInterface.class, new VpnInterfaceKey(vpnInterfaceName)).build();
     }
 
+    static InstanceIdentifier<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntryIdentifier(
+                                                             String vpnInterfaceName, String vpnName) {
+        return InstanceIdentifier.builder(VpnInterfaceOpData.class)
+            .child(VpnInterfaceOpDataEntry.class,
+            new VpnInterfaceOpDataEntryKey(vpnInterfaceName, vpnName)).build();
+    }
+
     static InstanceIdentifier<VpnInstance> getVpnInstanceIdentifier(String vpnName) {
         return InstanceIdentifier.builder(VpnInstances.class)
             .child(VpnInstance.class, new VpnInstanceKey(vpnName)).build();
@@ -204,12 +232,25 @@ public final class VpnUtil {
         return vpnInterface.isPresent() ? vpnInterface.get() : null;
     }
 
-    static VpnInterface getVpnInterface(String intfName, String vpnName, Adjacencies aug, BigInteger dpnId,
-        Boolean isSheduledForRemove) {
-        return new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(intfName)).setVpnInstanceName(vpnName).setDpnId(
-            dpnId)
-            .setScheduledForRemove(isSheduledForRemove).addAugmentation(Adjacencies.class, aug)
-            .build();
+    static VpnInterfaceOpDataEntry getVpnInterfaceOpDataEntry(String intfName, String vpnName,
+                                        AdjacenciesOp aug, BigInteger dpnId,
+                                        Boolean isSheduledForRemove, long lportTag, String gwMac) {
+        return new VpnInterfaceOpDataEntryBuilder().setKey(new VpnInterfaceOpDataEntryKey(intfName, vpnName))
+            .setDpnId(dpnId).setScheduledForRemove(isSheduledForRemove).addAugmentation(AdjacenciesOp.class, aug)
+                .setLportTag(lportTag).setGatewayMacAddress(gwMac).build();
+    }
+
+    static Optional<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntry(DataBroker broker,
+                                                    String vpnInterfaceName, String vpnName) {
+        InstanceIdentifier<VpnInterfaceOpDataEntry> id = getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName,
+                                                                                              vpnName);
+        Optional<VpnInterfaceOpDataEntry> vpnInterfaceOpDataEntry = read(broker,
+                                                      LogicalDatastoreType.OPERATIONAL, id);
+        return vpnInterfaceOpDataEntry;
+    }
+
+    static VpnInstanceNames getVpnInterfaceVpnInstanceNames(String vpnName, AssociatedSubnetType subnetType) {
+        return new VpnInstanceNamesBuilder().setVpnName(vpnName).setAssociatedSubnetType(subnetType).build();
     }
 
     static InstanceIdentifier<Prefixes> getPrefixToInterfaceIdentifier(long vpnId, String ipPrefix) {
@@ -302,7 +343,7 @@ public final class VpnUtil {
         return vpnInstance.isPresent() ? vpnInstance.get() : null;
     }
 
-    static List<VpnInstanceOpDataEntry> getAllVpnInstanceOpData(DataBroker broker) {
+    public static List<VpnInstanceOpDataEntry> getAllVpnInstanceOpData(DataBroker broker) {
         InstanceIdentifier<VpnInstanceOpData> id = InstanceIdentifier.builder(VpnInstanceOpData.class).build();
         Optional<VpnInstanceOpData> vpnInstanceOpDataOptional =
             VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, id);
@@ -386,6 +427,10 @@ public final class VpnUtil {
         return new AdjacenciesBuilder().setAdjacency(nextHopList).build();
     }
 
+    static AdjacenciesOp getVpnInterfaceOpDataEntryAugmentation(List<Adjacency> nextHopList) {
+        return new AdjacenciesOpBuilder().setAdjacency(nextHopList).build();
+    }
+
     public static InstanceIdentifier<IdPool> getPoolId(String poolName) {
         InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idBuilder =
             InstanceIdentifier.builder(IdPools.class).child(IdPool.class, new IdPoolKey(poolName));
@@ -714,28 +759,30 @@ public final class VpnUtil {
         return null;
     }
 
-    static VpnInterface getOperationalVpnInterface(DataBroker broker, String interfaceName) {
-        InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
-        Optional<VpnInterface> operationalVpnInterface = read(broker, LogicalDatastoreType.OPERATIONAL, interfaceId);
-
-        if (operationalVpnInterface.isPresent()) {
-            return operationalVpnInterface.get();
-        }
-        return null;
-    }
-
     static boolean isVpnInterfaceConfigured(DataBroker broker, String interfaceName) {
         InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
         return read(broker, LogicalDatastoreType.CONFIGURATION, interfaceId).isPresent();
     }
 
-    static Optional<String> getVpnAssociatedWithInterface(DataBroker broker, String interfaceName) {
+    static Optional<List<String>> getVpnHandlingIpv4AssociatedWithInterface(DataBroker broker, String interfaceName) {
         InstanceIdentifier<VpnInterface> interfaceId = getVpnInterfaceIdentifier(interfaceName);
-        Optional<String> vpnOptional = Optional.absent();
+        Optional<List<String>> vpnOptional = Optional.absent();
         Optional<VpnInterface> optConfiguredVpnInterface = read(broker, LogicalDatastoreType.CONFIGURATION,
                 interfaceId);
         if (optConfiguredVpnInterface.isPresent()) {
-            vpnOptional = Optional.of(optConfiguredVpnInterface.get().getVpnInstanceName());
+            VpnInterface cfgVpnInterface = optConfiguredVpnInterface.get();
+            java.util.Optional<List<VpnInstanceNames>> optVpnInstanceList =
+                 java.util.Optional.ofNullable(cfgVpnInterface.getVpnInstanceNames());
+            if (optVpnInstanceList.isPresent()) {
+                List<String> vpnList = new ArrayList<>();
+                for (VpnInstanceNames vpnInstance : optVpnInstanceList.get()) {
+                    if (vpnInstance.getAssociatedSubnetType().equals(AssociatedSubnetType.V6Subnet)) {
+                        continue;
+                    }
+                    vpnList.add(vpnInstance.getVpnName());
+                }
+                vpnOptional = Optional.of(vpnList);
+            }
         }
         return vpnOptional;
     }
@@ -830,7 +877,7 @@ public final class VpnUtil {
             tx.submit().get();
         } catch (InterruptedException | ExecutionException e) {
             LOG.error("syncWrite: Error writing to datastore (path, data) : ({}, {})", path, data);
-            throw new RuntimeException(e.getMessage());
+            throw new RuntimeException(e.getMessage(), e);
         }
     }
 
@@ -843,7 +890,7 @@ public final class VpnUtil {
             tx.submit().get();
         } catch (InterruptedException | ExecutionException e) {
             LOG.error("syncUpdate: Error writing to datastore (path, data) : ({}, {})", path, data);
-            throw new RuntimeException(e.getMessage());
+            throw new RuntimeException(e.getMessage(), e);
         }
     }
 
@@ -1041,10 +1088,12 @@ public final class VpnUtil {
     public static void scheduleVpnInterfaceForRemoval(DataBroker broker,String interfaceName, BigInteger dpnId,
                                                       String vpnInstanceName, Boolean isScheduledToRemove,
                                                       WriteTransaction writeOperTxn) {
-        InstanceIdentifier<VpnInterface> interfaceId = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
-        VpnInterface interfaceToUpdate =
-            new VpnInterfaceBuilder().setKey(new VpnInterfaceKey(interfaceName)).setName(interfaceName)
-                .setDpnId(dpnId).setVpnInstanceName(vpnInstanceName).setScheduledForRemove(isScheduledToRemove).build();
+        InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId =
+            VpnUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnInstanceName);
+        VpnInterfaceOpDataEntry interfaceToUpdate =
+            new VpnInterfaceOpDataEntryBuilder().setKey(new VpnInterfaceOpDataEntryKey(interfaceName,
+            vpnInstanceName)).setName(interfaceName).setDpnId(dpnId).setVpnInstanceName(vpnInstanceName)
+            .setScheduledForRemove(isScheduledToRemove).build();
         if (writeOperTxn != null) {
             writeOperTxn.merge(LogicalDatastoreType.OPERATIONAL, interfaceId, interfaceToUpdate, true);
         } else {
@@ -1261,10 +1310,12 @@ public final class VpnUtil {
             }
         } catch (InterruptedException | ExecutionException e) {
             LOG.error(errMsg);
-            throw new RuntimeException(errMsg, e.getCause());
+            throw new RuntimeException(e.getMessage(), e);
         }
     }
 
+    // We store the cause, which is what we really care about
+    @SuppressWarnings("checkstyle:AvoidHidingCauseException")
     public static void unlockSubnet(LockManagerService lockManager, String subnetId) {
         UnlockInput input = new UnlockInputBuilder().setLockName(subnetId).build();
         Future<RpcResult<Void>> result = lockManager.unlock(input);
@@ -1326,11 +1377,12 @@ public final class VpnUtil {
         return gatewayMac;
     }
 
-    public static boolean isVpnIntfPresentInVpnToDpnList(DataBroker broker, VpnInterface vpnInterface) {
+    public static boolean isVpnIntfPresentInVpnToDpnList(DataBroker broker,
+                                                      VpnInterface vpnInterface, String vpnName) {
         BigInteger dpnId = vpnInterface.getDpnId();
-        String rd = VpnUtil.getVpnRd(broker, vpnInterface.getVpnInstanceName());
+        String rd = VpnUtil.getVpnRd(broker, vpnName);
         LOG.trace("isVpnIntfPresentInVpnToDpnList: GOT rd {} for VpnInterface {}  VpnInstance {} ", rd ,
-                vpnInterface.getName(), vpnInterface.getVpnInstanceName());
+                 vpnInterface.getName(), vpnName);
         VpnInstanceOpDataEntry vpnInstanceOpData = VpnUtil.getVpnInstanceOpDataFromCache(broker, rd);
         if (vpnInstanceOpData != null) {
             LOG.trace("isVpnIntfPresentInVpnToDpnList: GOT VpnInstanceOp {} for rd {} ", vpnInstanceOpData, rd);
@@ -1342,7 +1394,7 @@ public final class VpnUtil {
                             vpnInterfaces -> vpnInterface.getName().equals(vpnInterfaces.getInterfaceName()));
                     }
                     LOG.info("isVpnIntfPresentInVpnToDpnList: VpnInterface {} not present in DpnId {} vpn {}",
-                            vpnInterface.getName(), dpn.getDpnId(), vpnInterface.getVpnInstanceName());
+                            vpnInterface.getName(), dpn.getDpnId(), vpnName);
                 }
             }
         }
@@ -1350,22 +1402,18 @@ public final class VpnUtil {
     }
 
     public static void setupGwMacIfExternalVpn(DataBroker dataBroker, IMdsalApiManager mdsalManager, BigInteger dpnId,
-            String interfaceName, long vpnId, WriteTransaction writeInvTxn, int addOrRemove, org.opendaylight.yang.gen
-            .v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState) {
+            String interfaceName, long vpnId, WriteTransaction writeInvTxn, int addOrRemove, String gwMac) {
         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance
             .VpnIds> vpnIdsInstanceIdentifier = getVpnIdToVpnInstanceIdentifier(vpnId);
         Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance
             .VpnIds> vpnIdsOptional = read(
                 dataBroker, LogicalDatastoreType.CONFIGURATION, vpnIdsInstanceIdentifier);
         if (vpnIdsOptional.isPresent() && vpnIdsOptional.get().isExternalVpn()) {
-            PhysAddress gwMacAddress = interfaceState.getPhysAddress();
-            if (gwMacAddress == null) {
+            if (gwMac == null) {
                 LOG.error("setupGwMacIfExternalVpn: Failed to get gwMacAddress for interface {} on dpn {} vpn {}",
                         interfaceName, dpnId.toString(), vpnIdsOptional.get().getVpnInstanceName());
                 return;
             }
-
-            String gwMac = gwMacAddress.getValue();
             FlowEntity flowEntity = VpnUtil.buildL3vpnGatewayFlow(dpnId, gwMac, vpnId, VpnConstants.INVALID_ID);
             if (addOrRemove == NwConstants.ADD_FLOW) {
                 mdsalManager.addFlowToTx(flowEntity, writeInvTxn);
@@ -1552,9 +1600,8 @@ public final class VpnUtil {
     }
 
     static void bindService(final String vpnInstanceName, final String interfaceName, DataBroker dataBroker,
-                            boolean isTunnelInterface) {
-        DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-        dataStoreCoordinator.enqueueJob(interfaceName,
+                            boolean isTunnelInterface, JobCoordinator jobCoordinator) {
+        jobCoordinator.enqueueJob(interfaceName,
             () -> {
                 WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
                 BoundServices serviceInfo = isTunnelInterface
@@ -1599,10 +1646,10 @@ public final class VpnUtil {
         return serviceInfo;
     }
 
-    static void unbindService(DataBroker dataBroker, final String vpnInterfaceName, boolean isInterfaceStateDown) {
+    static void unbindService(DataBroker dataBroker, final String vpnInterfaceName, boolean isInterfaceStateDown,
+            JobCoordinator jobCoordinator) {
         if (!isInterfaceStateDown) {
-            DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
-            dataStoreCoordinator.enqueueJob(vpnInterfaceName,
+            jobCoordinator.enqueueJob(vpnInterfaceName,
                 () -> {
                     WriteTransaction writeTxn = dataBroker.newWriteOnlyTransaction();
                     writeTxn.delete(LogicalDatastoreType.CONFIGURATION,
@@ -1717,4 +1764,197 @@ public final class VpnUtil {
         }
         return isVpnPendingDelete;
     }
+
+    public static List<VpnInstanceOpDataEntry> getVpnsImportingMyRoute(final DataBroker broker, final String vpnName) {
+        List<VpnInstanceOpDataEntry> vpnsToImportRoute = new ArrayList<>();
+
+        final String vpnRd = getVpnRd(broker, vpnName);
+        if (vpnRd == null) {
+            LOG.error("getVpnsImportingMyRoute: vpn {} not present in config DS.", vpnName);
+            return vpnsToImportRoute;
+        }
+        final VpnInstanceOpDataEntry vpnInstanceOpDataEntry = VpnUtil.getVpnInstanceOpData(broker, vpnRd);
+        if (vpnInstanceOpDataEntry == null) {
+            LOG.error("getVpnsImportingMyRoute: Could not retrieve vpn instance op data for {}"
+                    + " to check for vpns importing the routes", vpnName);
+            return vpnsToImportRoute;
+        }
+
+        Predicate<VpnInstanceOpDataEntry> excludeVpn = input -> {
+            if (input.getVpnInstanceName() == null) {
+                LOG.error("getVpnsImportingMyRoute.excludeVpn: Received vpn instance with rd {} without a name.",
+                        input.getVrfId());
+                return false;
+            }
+            return !input.getVpnInstanceName().equals(vpnName);
+        };
+
+        Predicate<VpnInstanceOpDataEntry> matchRTs = input -> {
+            Iterable<String> commonRTs =
+                intersection(getRts(vpnInstanceOpDataEntry, VpnTarget.VrfRTType.ExportExtcommunity),
+                    getRts(input, VpnTarget.VrfRTType.ImportExtcommunity));
+            return Iterators.size(commonRTs.iterator()) > 0;
+        };
+
+        vpnsToImportRoute = getAllVpnInstanceOpData(broker)
+                .stream()
+                .filter(excludeVpn)
+                .filter(matchRTs)
+                .collect(Collectors.toList());
+        return vpnsToImportRoute;
+    }
+
+    public static List<String> getRts(VpnInstanceOpDataEntry vpnInstance, VpnTarget.VrfRTType rtType) {
+        String name = vpnInstance.getVpnInstanceName();
+        List<String> rts = new ArrayList<>();
+        VpnTargets targets = vpnInstance.getVpnTargets();
+        if (targets == null) {
+            LOG.info("getRts: vpn targets not available for {}", name);
+            return rts;
+        }
+        List<VpnTarget> vpnTargets = targets.getVpnTarget();
+        if (vpnTargets == null) {
+            LOG.info("getRts: vpnTarget values not available for {}", name);
+            return rts;
+        }
+        for (VpnTarget target : vpnTargets) {
+            //TODO: Check for RT type is Both
+            if (target.getVrfRTType().equals(rtType) || target.getVrfRTType().equals(VpnTarget.VrfRTType.Both)) {
+                String rtValue = target.getVrfRTValue();
+                rts.add(rtValue);
+            }
+        }
+        return rts;
+    }
+
+    public static <T> Iterable<T> intersection(final Collection<T> collection1, final Collection<T> collection2) {
+        Set<T> intersection = new HashSet<>(collection1);
+        intersection.retainAll(collection2);
+        return intersection;
+    }
+
+    /** Get Subnetmap from its Uuid.
+     * @param broker the data broker for look for data
+     * @param subnetUuid the subnet's Uuid
+     * @return the Subnetmap of Uuid or null if it is not found
+     */
+    public static Subnetmap getSubnetmapFromItsUuid(DataBroker broker, Uuid subnetUuid) {
+        Subnetmap sn = null;
+        InstanceIdentifier<Subnetmap> id = buildSubnetmapIdentifier(subnetUuid);
+        Optional<Subnetmap> optionalSn = read(broker, LogicalDatastoreType.CONFIGURATION, id);
+        if (optionalSn.isPresent()) {
+            sn = optionalSn.get();
+        }
+        return sn;
+    }
+
+    public static boolean isSubnetPartOfVpn(Subnetmap sn, String vpnName) {
+        if (vpnName == null || sn == null || sn.getVpnId() == null) {
+            return false;
+        }
+        if (sn.getVpnId().getValue().equals(vpnName)) {
+            return true;
+        } else if (sn.getInternetVpnId() != null
+                && sn.getInternetVpnId().getValue().equals(vpnName)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean isAdjacencyEligibleToVpnInternet(DataBroker dataBroker, Adjacency adjacency) {
+        // returns true if BGPVPN Internet and adjacency is IPv6, false otherwise
+        boolean adjacencyEligible = true;
+        if (adjacency.getAdjacencyType() == AdjacencyType.ExtraRoute) {
+            if (FibHelper.isIpv6Prefix(adjacency.getIpAddress())) {
+                return adjacencyEligible;
+            }
+            return false;
+        } else if (adjacency.getSubnetId() == null) {
+            return adjacencyEligible;
+        }
+        Subnetmap sn = VpnUtil.getSubnetmapFromItsUuid(
+                   dataBroker, adjacency.getSubnetId());
+        if (sn != null && sn.getInternetVpnId() != null) {
+            adjacencyEligible = false;
+        }
+        return adjacencyEligible;
+    }
+
+    public static boolean isAdjacencyEligibleToVpn(DataBroker dataBroker, Adjacency adjacency,
+                      String vpnName, String interfaceName) {
+        // returns true if BGPVPN Internet and adjacency is IPv6, false otherwise
+        boolean adjacencyEligible = true;
+        // if BGPVPN internet, return false if subnetmap has not internetVpnId() filled in
+        if (isBgpVpnInternet(dataBroker, vpnName)) {
+            return isAdjacencyEligibleToVpnInternet(dataBroker, adjacency);
+        }
+        return adjacencyEligible;
+    }
+
+    public static String getInternetVpnFromVpnInstanceList(DataBroker dataBroker,
+                                        List<VpnInstanceNames> vpnInstanceList) {
+        for (VpnInstanceNames vpnInstance : vpnInstanceList) {
+            String vpnName = vpnInstance.getVpnName();
+            if (isBgpVpnInternet(dataBroker, vpnName)) {
+                return vpnName;
+            }
+        }
+        return null;
+    }
+
+    /** Get boolean true if vpn is bgpvpn internet, false otherwise.
+     * @param dataBroker databroker for transaction
+     * @param vpnName name of the input VPN
+     * @return true or false
+     */
+    public static boolean isBgpVpnInternet(DataBroker dataBroker, String vpnName) {
+        String primaryRd = getVpnRd(dataBroker, vpnName);
+        if (primaryRd == null) {
+            LOG.error("isBgpVpnInternet VPN {}."
+                      + "Primary RD not found", vpnName);
+            return false;
+        }
+        InstanceIdentifier<VpnInstanceOpDataEntry> id = InstanceIdentifier.builder(VpnInstanceOpData.class)
+              .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(primaryRd)).build();
+
+        Optional<VpnInstanceOpDataEntry> vpnInstanceOpDataEntryOptional =
+            read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        if (!vpnInstanceOpDataEntryOptional.isPresent()) {
+            LOG.error("isBgpVpnInternet VPN {}."
+                     + "VpnInstanceOpDataEntry not found", vpnName);
+            return false;
+        }
+        LOG.debug("isBgpVpnInternet VPN {}."
+             + "Successfully VpnInstanceOpDataEntry.getBgpvpnType {}",
+             vpnName, vpnInstanceOpDataEntryOptional.get().getBgpvpnType());
+        if (vpnInstanceOpDataEntryOptional.get().getBgpvpnType() == VpnInstanceOpDataEntry
+               .BgpvpnType.BGPVPNInternet) {
+            return true;
+        }
+        return false;
+    }
+
+    /**Get IpVersionChoice from String IP like x.x.x.x or an representation IPv6.
+     * @param ipAddress String of an representation IP address V4 or V6
+     * @return the IpVersionChoice of the version or IpVersionChoice.UNDEFINED otherwise
+     */
+    public static IpVersionChoice getIpVersionFromString(String ipAddress) {
+        IpVersionChoice ipchoice = IpVersionChoice.UNDEFINED;
+        int indexIpAddress = ipAddress.indexOf('/');
+        if (indexIpAddress >= 0) {
+            ipAddress = ipAddress.substring(0, indexIpAddress);
+        }
+        try {
+            InetAddress address = InetAddress.getByName(ipAddress);
+            if (address instanceof Inet4Address) {
+                return IpVersionChoice.IPV4;
+            } else if (address instanceof Inet6Address) {
+                return IpVersionChoice.IPV6;
+            }
+        } catch (UnknownHostException | SecurityException e) {
+            ipchoice = IpVersionChoice.UNDEFINED;
+        }
+        return ipchoice;
+    }
+
 }