Lower log levels for non error's
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnSubnetRouteHandler.java
index 6ae2278aa34c76c93aaf7ab06a0cfb0892076e56..1df2f5d14e0697a351366e5df9e15f890caffcdc 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -21,7 +22,11 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.VpnOpDataSyncer.VpnOpDataType;
+import org.opendaylight.netvirt.vpnmanager.populator.input.L3vpnInput;
+import org.opendaylight.netvirt.vpnmanager.populator.intfc.VpnPopulator;
+import org.opendaylight.netvirt.vpnmanager.populator.registry.L3vpnRegistry;
 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
@@ -34,6 +39,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Sub
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.TaskState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
 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.SubnetOpDataEntryBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.subnet.op.data.SubnetOpDataEntryKey;
@@ -50,6 +56,7 @@ import org.slf4j.LoggerFactory;
 
 public class VpnSubnetRouteHandler {
     private static final Logger LOG = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
+    private static final String LOGGING_PREFIX = "SUBNETROUTE:";
     private final DataBroker dataBroker;
     private final SubnetOpDpnManager subOpDpnManager;
     private final IBgpManager bgpManager;
@@ -57,10 +64,12 @@ public class VpnSubnetRouteHandler {
     private final IdManagerService idManager;
     private LockManagerService lockManager;
     private final VpnOpDataSyncer vpnOpDataSyncer;
+    private final VpnNodeListener vpnNodeListener;
 
     public VpnSubnetRouteHandler(final DataBroker dataBroker, final SubnetOpDpnManager subnetOpDpnManager,
         final IBgpManager bgpManager, final VpnInterfaceManager vpnIntfManager, final IdManagerService idManager,
-        LockManagerService lockManagerService, final VpnOpDataSyncer vpnOpDataSyncer) {
+        LockManagerService lockManagerService, final VpnOpDataSyncer vpnOpDataSyncer,
+        final VpnNodeListener vpnNodeListener) {
         this.dataBroker = dataBroker;
         this.subOpDpnManager = subnetOpDpnManager;
         this.bgpManager = bgpManager;
@@ -68,41 +77,52 @@ public class VpnSubnetRouteHandler {
         this.idManager = idManager;
         this.lockManager = lockManagerService;
         this.vpnOpDataSyncer = vpnOpDataSyncer;
+        this.vpnNodeListener = vpnNodeListener;
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void onSubnetAddedToVpn(Subnetmap subnetmap, boolean isBgpVpn, Long elanTag) {
         Uuid subnetId = subnetmap.getId();
-        String vpnName = subnetmap.getVpnId().getValue();
         String subnetIp = subnetmap.getSubnetIp();
-        boolean isRouteAdvertised = false;
-
-        Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
-        Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
-        Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
-        Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
-
-        LOG.info("onSubnetAddedToVpn: Subnet {} being added to vpn", subnetId.getValue());
-
-        long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
-        if (vpnId == VpnConstants.INVALID_ID) {
-            vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataType.vpnInstanceToId, vpnName,
-                VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
-            vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
+        Subnetmap subMap = null;
+        SubnetOpDataEntry subOpEntry = null;
+        SubnetOpDataEntryBuilder subOpBuilder = null;
+        InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier = null;
+        Optional<SubnetOpDataEntry> optionalSubs = null;
+
+        Preconditions.checkNotNull(subnetId, LOGGING_PREFIX + " onSubnetAddedToVpn: SubnetId cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp,
+                LOGGING_PREFIX + " onSubnetAddedToVpn: SubnetPrefix cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, LOGGING_PREFIX + " onSubnetAddedToVpn: ElanTag cannot be null or empty!");
+
+        String vpnName;
+        if (subnetmap.getVpnId() != null) {
+            vpnName = subnetmap.getVpnId().getValue();
+            long vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
             if (vpnId == VpnConstants.INVALID_ID) {
-                LOG.error(
-                    "onSubnetAddedToVpn: VpnInstance to VPNId mapping not yet available for VpnName {} processing "
-                        + "subnet {} with IP {}, bailing out now.", vpnName, subnetId, subnetIp);
-                return;
+                vpnOpDataSyncer.waitForVpnDataReady(VpnOpDataType.vpnInstanceToId, vpnName,
+                        VpnConstants.PER_VPN_INSTANCE_MAX_WAIT_TIME_IN_MILLISECONDS);
+                vpnId = VpnUtil.getVpnId(dataBroker, vpnName);
+                if (vpnId == VpnConstants.INVALID_ID) {
+                    LOG.error("{} onSubnetAddedToVpn: VpnInstance to VPNId mapping not yet available for VpnName {} "
+                              + "processing subnet {} with IP {}, bailing out now.", LOGGING_PREFIX, vpnName, subnetId,
+                            subnetIp);
+                    return;
+                }
             }
+        } else {
+            LOG.error("onSubnetAddedToVpn: VpnId {} for subnet {} not found, bailing out", subnetmap.getVpnId(),
+                      subnetId);
+            return;
         }
+        LOG.info("{} onSubnetAddedToVpn: Subnet {} with IP {}being added to vpn {}", LOGGING_PREFIX,
+                subnetId.getValue(), subnetIp, vpnName);
 
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
-                Subnetmap subMap = null;
 
                 // Please check if subnetId belongs to an External Network
                 InstanceIdentifier<Subnetmap> subMapid =
@@ -110,7 +130,8 @@ public class VpnSubnetRouteHandler {
                         new SubnetmapKey(subnetId)).build();
                 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
                 if (!sm.isPresent()) {
-                    LOG.error("onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet : " + subnetId);
+                    LOG.error("{} onSubnetAddedToVpn: Unable to retrieve subnetmap entry for subnet {} IP {}"
+                            + " vpnName {}",  LOGGING_PREFIX, subnetId, subnetIp, vpnName);
                     return;
                 }
                 subMap = sm.get();
@@ -121,78 +142,93 @@ public class VpnSubnetRouteHandler {
                     Optional<Networks> optionalNets = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
                             netsIdentifier);
                     if (optionalNets.isPresent()) {
-                        LOG.info("onSubnetAddedToVpn: subnet {} is an external subnet on external network" + " {},"
-                                + " so ignoring this" + " for SubnetRoute",
-                                subnetId.getValue(), subMap.getNetworkId().getValue());
+                        LOG.info("{} onSubnetAddedToVpn: subnet {} with IP {} is an external subnet on external "
+                                + "network {}, so ignoring this for SubnetRoute on vpn {}", LOGGING_PREFIX,
+                                subnetId.getValue(), subnetIp, subMap.getNetworkId().getValue(), vpnName);
                         return;
                     }
                 }
                 //Create and add SubnetOpDataEntry object for this subnet to the SubnetOpData container
-                InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
-                    InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
+                subOpIdentifier = InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
                         new SubnetOpDataEntryKey(subnetId)).build();
-                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
-                        LogicalDatastoreType.OPERATIONAL,
-                        subOpIdentifier);
+                optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
                 if (optionalSubs.isPresent()) {
-                    LOG.error("onSubnetAddedToVpn: SubnetOpDataEntry for subnet {} already detected to be present",
-                        subnetId.getValue());
+                    LOG.error("{} onSubnetAddedToVpn: SubnetOpDataEntry for subnet {} with ip {} and vpn {} already"
+                            + " detected to be present", LOGGING_PREFIX, subnetId.getValue(), subnetIp, vpnName);
                     return;
                 }
-                LOG.debug("onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet: " + subnetId.getValue());
-                Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<>();
-                BigInteger dpnId = null;
-                BigInteger nhDpnId = null;
-                SubnetToDpn subDpn = null;
-
-                SubnetOpDataEntryBuilder subOpBuilder =
-                    new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
+                LOG.debug("{} onSubnetAddedToVpn: Creating new SubnetOpDataEntry node for subnet {} subnetIp {}"
+                        + "vpn {}", LOGGING_PREFIX, subnetId.getValue(), subnetIp, vpnName);
+                subOpBuilder = new SubnetOpDataEntryBuilder().setKey(new SubnetOpDataEntryKey(subnetId));
                 subOpBuilder.setSubnetId(subnetId);
                 subOpBuilder.setSubnetCidr(subnetIp);
                 String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
 
                 if (isBgpVpn && !VpnUtil.isBgpVpn(vpnName, primaryRd)) {
-                    LOG.error("onSubnetAddedToVpn: The VPN Instance name " + vpnName + " does not have RD ");
+                    LOG.error("{} onSubnetAddedToVpn: The VPN Instance name {} does not have RD. Bailing out for"
+                            + " subnet {} subnetIp {} ", LOGGING_PREFIX, vpnName, subnetId.getValue(), subnetIp);
                     return;
                 }
 
                 subOpBuilder.setVrfId(primaryRd);
                 subOpBuilder.setVpnName(vpnName);
                 subOpBuilder.setSubnetToDpn(new ArrayList<>());
-                subOpBuilder.setRouteAdvState(TaskState.Na);
+                subOpBuilder.setRouteAdvState(TaskState.Idle);
                 subOpBuilder.setElanTag(elanTag);
+                Long l3Vni = VpnUtil.getVpnInstanceOpData(dataBroker, primaryRd).getL3vni();
+                subOpBuilder.setL3vni(l3Vni);
+
+                subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                LOG.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet {}",
+                        subnetId.getValue());
+            } catch (Exception ex) {
+                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed ", subnetId.getValue(), ex);
+            } finally {
+                VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
+            }
+
+            //In second critical section , Port-Op-Data will be updated.
+            VpnUtil.lockSubnet(lockManager, subnetId.getValue());
+            try {
+                BigInteger dpnId = null;
+                SubnetToDpn subDpn = null;
+                Map<BigInteger, SubnetToDpn> subDpnMap = new HashMap<BigInteger, SubnetToDpn>();
 
-                // First recover set of ports available in this subnet
+                optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
+                subOpBuilder =
+                        new SubnetOpDataEntryBuilder(optionalSubs.get()).setKey(new SubnetOpDataEntryKey(subnetId));
                 List<Uuid> portList = subMap.getPortList();
                 if (portList != null) {
-                    for (Uuid port: portList) {
+                    for (Uuid port : portList) {
                         Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,port.getValue());
                         if (intfState != null) {
                             try {
                                 dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
                             } catch (Exception e) {
-                                LOG.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},",
-                                        " subnetroute inclusion for this interface failed with exception {}",
-                                        port.getValue(), e);
+                                LOG.error("{} onSubnetAddedToVpn: Unable to obtain dpnId for interface {},"
+                                        + " subnetroute inclusion for this interface for subnet {} subnetIp {} vpn {}"
+                                        + " failed with exception {}", LOGGING_PREFIX, port.getValue(),
+                                        subnetId.getValue(), subnetIp, vpnName, e);
                                 continue;
                             }
                             if (dpnId.equals(BigInteger.ZERO)) {
-                                LOG.info("onSubnetAddedToVpn: Port " + port.getValue()
-                                    + " is not assigned DPN yet, ignoring ");
+                                LOG.error("{} onSubnetAddedToVpn: Port {} is not assigned DPN yet,"
+                                        + " ignoring subnet {} subnetIP {} vpn {}", LOGGING_PREFIX, port.getValue(),
+                                        subnetId.getValue(), subnetIp, vpnName);
                                 continue;
                             }
                             subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, dpnId);
                             if (intfState.getOperStatus() != OperStatus.Up) {
-                                LOG.info("onSubnetAddedToVpn: Port " + port.getValue() + " is not UP yet, ignoring ");
+                                LOG.error("{} onSubnetAddedToVpn: Port {} is not UP yet, ignoring subnet {}"
+                                        + " subnetIp {} vpn {}", LOGGING_PREFIX, port.getValue(), subnetId.getValue(),
+                                        subnetIp, vpnName);
                                 continue;
                             }
                             subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, port.getValue());
                             if (intfState.getOperStatus() == OperStatus.Up) {
                                 // port is UP
                                 subDpnMap.put(dpnId, subDpn);
-                                if (nhDpnId == null) {
-                                    nhDpnId = dpnId;
-                                }
                             }
                         } else {
                             subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
@@ -202,58 +238,23 @@ public class VpnSubnetRouteHandler {
                         subOpBuilder.setSubnetToDpn(new ArrayList<>(subDpnMap.values()));
                     }
                 }
-
-                if (nhDpnId != null) {
-                    LOG.info("Next-Hop dpn {} is available for rd {} subnetIp {} vpn {}", nhDpnId, primaryRd,
-                        subnetIp, vpnName);
-                    subOpBuilder.setNhDpnId(nhDpnId);
-                    try {
-                        /*
-                        Write the subnet route entry to the FIB.
-                        And also advertise the subnet route entry via BGP.
-                        */
-                        int label = getLabel(primaryRd, subnetIp);
-                        if (label == 0) {
-                            LOG.error(
-                                "Unable to fetch label from Id Manager. Bailing out of handling addition of subnet {}"
-                                    + " to vpn {}",
-                                subnetIp, vpnName);
-                            return;
-                        }
-                        isRouteAdvertised =
-                            addSubnetRouteToFib(primaryRd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId,
-                                    isBgpVpn, subMap.getNetworkId().getValue());
-                        if (isRouteAdvertised) {
-                            subOpBuilder.setRouteAdvState(TaskState.Done);
-                        } else {
-                            subOpBuilder.setNhDpnId(null);
-                            subOpBuilder.setRouteAdvState(TaskState.Na);
-                        }
-                    } catch (Exception ex) {
-                        LOG.error(
-                            "onSubnetAddedToVpn: FIB rules and Advertising nhDpnId {} information for subnet {} to "
-                                + "BGP failed",
-                            nhDpnId, subnetId.getValue(), ex);
-                        subOpBuilder.setRouteAdvState(TaskState.Pending);
-                    }
-                } else if (!isBgpVpn) {
-                    addSubnetRouteToFib(primaryRd, subnetIp, null, vpnName, elanTag, 0, subnetId, false,
-                            subMap.getNetworkId().getValue());
-                } else {
-                    LOG.info("Next-Hop dpn is unavailable for rd {} subnetIp {} vpn {}", primaryRd, subnetIp, vpnName);
-                }
-
-                SubnetOpDataEntry subOpEntry = subOpBuilder.build();
-                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                LOG.info("onSubnetAddedToVpn: Added subnetopdataentry to OP Datastore for subnet {}",
-                        subnetId.getValue());
+                electNewDpnForSubnetRoute(subOpBuilder, null /* oldDpnId */, subnetId,
+                        subMap.getNetworkId(), isBgpVpn);
+                subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                LOG.info("{} onSubnetAddedToVpn: Added PortOpDataEntry and VpnInterfaces to SubnetOpData"
+                                + " for subnet {} subnetIp {} vpn {} TaskState {} lastTaskState {}", LOGGING_PREFIX,
+                        subnetId.getValue(), subnetIp, vpnName, subOpEntry.getRouteAdvState(),
+                        subOpEntry.getLastAdvState());
             } catch (Exception ex) {
-                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} onSubnetAddedToVpn: Creation of SubnetOpDataEntry for subnet {} subnetIp {} vpn {}"
+                        + " failed {}", LOGGING_PREFIX, subnetId.getValue(), subnetIp, vpnName, ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle subnet {} added to vpn {} {}", subnetIp, vpnName, e);
+            LOG.error("{} onSubnetAddedToVpn: Unable to handle subnet {} with ip {} added to vpn {} {}", LOGGING_PREFIX,
+                    subnetId.getValue(), subnetIp, vpnName, e);
         }
     }
 
@@ -261,7 +262,8 @@ public class VpnSubnetRouteHandler {
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void onSubnetDeletedFromVpn(Subnetmap subnetmap, boolean isBgpVpn) {
         Uuid subnetId = subnetmap.getId();
-        LOG.info("onSubnetDeletedFromVpn: Subnet " + subnetId.getValue() + " being removed from vpn");
+        LOG.info("{} onSubnetDeletedFromVpn: Subnet {} with ip {} being removed from vpnId {}", LOGGING_PREFIX,
+                subnetId, subnetmap.getSubnetIp(), subnetmap.getVpnId());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -269,16 +271,19 @@ public class VpnSubnetRouteHandler {
                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
                         new SubnetOpDataEntryKey(subnetId)).build();
-                LOG.trace(" Removing the SubnetOpDataEntry node for subnet: " +  subnetId.getValue());
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
                         LogicalDatastoreType.OPERATIONAL,
                         subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.error("onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet {} not available in datastore",
-                        subnetId.getValue());
+                    LOG.error("{} onSubnetDeletedFromVpn: SubnetOpDataEntry for subnet {} subnetIp {} vpn {}"
+                            + " not available in datastore", LOGGING_PREFIX, subnetId.getValue(),
+                            subnetId.getValue(), subnetmap.getVpnId());
                     return;
                 }
-
+                LOG.trace("{} onSubnetDeletedFromVpn: Removing the SubnetOpDataEntry node for subnet {} subnetIp {}"
+                        + " vpnName {} rd {} TaskState {}", LOGGING_PREFIX, subnetId.getValue(),
+                        optionalSubs.get().getSubnetCidr(), optionalSubs.get().getVpnName(),
+                        optionalSubs.get().getVrfId(), optionalSubs.get().getRouteAdvState());
                 /* If subnet is deleted (or if its removed from VPN), the ports that are DOWN on that subnet
                  * will continue to be stale in portOpData DS, as subDpnList used for portOpData removal will
                  * contain only ports that are UP. So here we explicitly cleanup the ports of the subnet by
@@ -289,7 +294,9 @@ public class VpnSubnetRouteHandler {
                         new SubnetmapKey(subnetId)).build();
                 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
                 if (!sm.isPresent()) {
-                    LOG.error("Stale ports removal: Unable to retrieve subnetmap entry for subnet : " + subnetId);
+                    LOG.error("{} onSubnetDeletedFromVpn: Stale ports removal: Unable to retrieve subnetmap entry"
+                            + " for subnet {} subnetIp {} vpnName {}", LOGGING_PREFIX, subnetId.getValue(),
+                            optionalSubs.get().getSubnetCidr(), optionalSubs.get().getVpnName());
                 } else {
                     Subnetmap subMap = sm.get();
                     List<Uuid> portList = subMap.getPortList();
@@ -298,7 +305,11 @@ public class VpnSubnetRouteHandler {
                             InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
                                 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
                                     new PortOpDataEntryKey(port.getValue())).build();
-                            LOG.trace("Deleting portOpData entry for port " + port.getValue());
+                            LOG.trace("{} onSubnetDeletedFromVpn: Deleting portOpData entry for port {}"
+                                    + " from subnet {} subnetIp {} vpnName {} TaskState()",
+                                    LOGGING_PREFIX, port.getValue(), subnetId.getValue(),
+                                    optionalSubs.get().getSubnetCidr(), optionalSubs.get().getVpnName(),
+                                    optionalSubs.get().getRouteAdvState());
                             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
                         }
                     }
@@ -308,38 +319,37 @@ public class VpnSubnetRouteHandler {
                 String rd = subOpBuilder.getVrfId();
                 String subnetIp = subOpBuilder.getSubnetCidr();
                 String vpnName = subOpBuilder.getVpnName();
-                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
+                //Withdraw the routes for all the interfaces on this subnet
+                //Remove subnet route entry from FIB
+                deleteSubnetRouteFromFib(rd, subnetIp, vpnName, isBgpVpn);
                 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
-                LOG.info("onSubnetDeletedFromVpn: Removed subnetopdataentry for subnet {} successfully from Datastore",
-                    subnetId.getValue());
-                try {
-                    //Withdraw the routes for all the interfaces on this subnet
-                    //Remove subnet route entry from FIB
-                    deleteSubnetRouteFromFib(rd, subnetIp, vpnName, isBgpVpn);
-                } catch (Exception ex) {
-                    LOG.error("onSubnetAddedToVpn: Withdrawing routes from BGP for subnet {} failed",
-                        subnetId.getValue(), ex);
-                }
+                LOG.info("{} onSubnetDeletedFromVpn: Removed subnetopdataentry successfully from Datastore"
+                        + " for subnet {} subnetIp {} vpnName {} rd {}", LOGGING_PREFIX, subnetId.getValue(), subnetIp,
+                        vpnName, rd);
             } catch (Exception ex) {
-                LOG.error("Removal of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} onSubnetDeletedFromVpn: Removal of SubnetOpDataEntry for subnet {} subnetIp {}"
+                        + " vpnId {} failed {}", LOGGING_PREFIX, subnetId.getValue(), subnetmap.getSubnetIp(),
+                        subnetmap.getVpnId(), ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle subnet {} removed to vpn {}", subnetmap.getSubnetIp(),
-                subnetmap.getVpnId().getValue(), e);
+            LOG.error("{} onSubnetDeletedFromVpn: Unable to handle subnet {} with Ip {} removed from vpn {} {}",
+                    LOGGING_PREFIX, subnetId.getValue(), subnetmap.getSubnetIp(), subnetmap.getVpnId(), e);
         }
     }
 
-    public void onSubnetUpdatedInVpn(Subnetmap subnetmap, boolean isBgpVpn, Long elanTag) {
+    public void onSubnetUpdatedInVpn(Subnetmap subnetmap, Long elanTag) {
         Uuid subnetId = subnetmap.getId();
         String vpnName = subnetmap.getVpnId().getValue();
         String subnetIp = subnetmap.getSubnetIp();
 
-        Preconditions.checkNotNull(subnetId, "SubnetId cannot be null or empty!");
-        Preconditions.checkNotNull(subnetIp, "SubnetPrefix cannot be null or empty!");
-        Preconditions.checkNotNull(vpnName, "VpnName cannot be null or empty!");
-        Preconditions.checkNotNull(elanTag, "ElanTag cannot be null or empty!");
+        Preconditions.checkNotNull(subnetId,
+                LOGGING_PREFIX + " onSubnetUpdatedInVpn: SubnetId cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp,
+                LOGGING_PREFIX + " onSubnetUpdatedInVpn: SubnetPrefix cannot be null or empty!");
+        Preconditions.checkNotNull(vpnName, LOGGING_PREFIX + " onSubnetUpdatedInVpn: VpnName cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, LOGGING_PREFIX + " onSubnetUpdatedInVpn: ElanTag cannot be null or empty!");
 
         InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
             InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
@@ -347,25 +357,20 @@ public class VpnSubnetRouteHandler {
         Optional<SubnetOpDataEntry> optionalSubs =
             VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
         if (optionalSubs.isPresent()) {
-            if (!isBgpVpn) {
-                onSubnetDeletedFromVpn(subnetmap, !isBgpVpn);
-            }
-        // TODO(vivek): Something got updated, but we donot know what ?
+            onSubnetDeletedFromVpn(subnetmap, true);
         } else {
-            if (isBgpVpn) {
-                onSubnetAddedToVpn(subnetmap, isBgpVpn, elanTag);
-            }
-        // TODO(vivek): Something got updated, but we donot know what ?
+            onSubnetAddedToVpn(subnetmap, true, elanTag);
         }
+        LOG.info("{} onSubnetUpdatedInVpn: subnet {} with Ip {} updated successfully for vpn {}", LOGGING_PREFIX,
+                subnetId.getValue(), subnetIp, vpnName);
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void onPortAddedToSubnet(Subnetmap subnetmap, Uuid portId) {
         Uuid subnetId = subnetmap.getId();
-        boolean isRouteAdvertised = false;
-
-        LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
+        LOG.info("{} onPortAddedToSubnet: Port {} being added to subnet {}", LOGGING_PREFIX, portId.getValue(),
+                subnetId.getValue());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -377,91 +382,86 @@ public class VpnSubnetRouteHandler {
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                         subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.info("onPortAddedToSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring",
-                        portId.getValue(), subnetId.getValue());
+                    LOG.info("{} onPortAddedToSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring",
+                            LOGGING_PREFIX, portId.getValue(), subnetId.getValue());
                     return;
                 }
+                String vpnName = optionalSubs.get().getVpnName();
+                String subnetIp = optionalSubs.get().getSubnetCidr();
+                String rd = optionalSubs.get().getVrfId();
+                String routeAdvState = optionalSubs.get().getRouteAdvState().toString();
+                LOG.info("{} onPortAddedToSubnet: Port {} being added to subnet {} subnetIp {} vpnName {} rd {} "
+                                + "TaskState {}", LOGGING_PREFIX, portId.getValue(), subnetId.getValue(), subnetIp,
+                        vpnName, rd, routeAdvState);
+                subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
                 Interface intfState = InterfaceUtils.getInterfaceStateFromOperDS(dataBroker,portId.getValue());
                 if (intfState == null) {
                     // Interface State not yet available
-                    subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, null);
                     return;
                 }
                 BigInteger dpnId = BigInteger.ZERO;
                 try {
                     dpnId = InterfaceUtils.getDpIdFromInterface(intfState);
                 } catch (Exception e) {
-                    LOG.error("onSubnetAddedToVpn: Unable to obtain dpnId for interface {},",
-                            " subnetroute inclusion for this interface failed with exception {}",
-                            portId.getValue(), e);
+                    LOG.error("{} onPortAddedToSubnet: Unable to obtain dpnId for interface {}. subnetroute inclusion"
+                                    + " for this interface failed for subnet {} subnetIp {} vpn {} rd {} with "
+                                    + "exception {}", LOGGING_PREFIX, portId.getValue(), subnetId.getValue(), subnetIp,
+                            vpnName, rd, e);
                     return;
                 }
                 if (dpnId.equals(BigInteger.ZERO)) {
-                    LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not assigned DPN yet, ignoring ");
+                    LOG.error("{} onPortAddedToSubnet: Port {} is not assigned DPN yet, ignoring subnetRoute "
+                                    + "inclusion for the interface into subnet {} subnetIp {} vpnName {} rd {}",
+                            LOGGING_PREFIX, portId.getValue(), subnetId.getValue(), subnetIp, vpnName, rd);
                     return;
                 }
                 subOpDpnManager.addPortOpDataEntry(portId.getValue(), subnetId, dpnId);
                 if (intfState.getOperStatus() != OperStatus.Up) {
-                    LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " is not UP yet, ignoring ");
+                    LOG.error("{} onPortAddedToSubnet: Port {} is not UP yet, ignoring subnetRoute inclusion for "
+                                    + "the interface into subnet {} subnetIp {} vpnName {} rd {}", LOGGING_PREFIX,
+                            portId.getValue(), subnetId.getValue(), subnetIp, vpnName, rd);
                     return;
                 }
-                LOG.debug("onPortAddedToSubnet: Updating the SubnetOpDataEntry node for subnet {}",
-                    subnetId.getValue());
+                LOG.debug("{} onPortAddedToSubnet: Port {} added. Updating the SubnetOpDataEntry node for subnet {} "
+                                + "subnetIp {} vpnName {} rd {} TaskState {}", LOGGING_PREFIX, portId.getValue(),
+                        subnetId.getValue(), subnetIp, vpnName, rd, routeAdvState);
                 SubnetToDpn subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, portId.getValue());
                 if (subDpn == null) {
+                    LOG.error("{} onPortAddedToSubnet: subnet-to-dpn list is null for subnetId {}. portId {}, "
+                                    + "vpnName {}, rd {}, subnetIp {}", LOGGING_PREFIX, subnetId.getValue(),
+                            portId.getValue(), vpnName, rd, subnetIp);
                     return;
                 }
-                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                SubnetOpDataEntry subnetOpDataEntry = optionalSubs.get();
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(subnetOpDataEntry);
                 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
                 subDpnList.add(subDpn);
                 subOpBuilder.setSubnetToDpn(subDpnList);
-                if (subOpBuilder.getNhDpnId()  == null) {
-                    subOpBuilder.setNhDpnId(dpnId);
-                }
-                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
-                String rd = subOpBuilder.getVrfId();
-                String subnetIp = subOpBuilder.getSubnetCidr();
-                String vpnName = subOpBuilder.getVpnName();
-                Long elanTag = subOpBuilder.getElanTag();
-                if ((subOpBuilder.getRouteAdvState() == TaskState.Pending)
-                    || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
-                    try {
-                        // Write the Subnet Route Entry to FIB
-                        // Advertise BGP Route here and set route_adv_state to DONE
-                        int label = getLabel(rd, subnetIp);
-                        if (label == 0) {
-                            LOG.error(
-                                "Unable to fetch label from Id Manager. Bailing out of handling addition of port {} "
-                                    + "to subnet {} in vpn {}",
-                                portId.getValue(), subnetIp, vpnName);
-                            return;
-                        }
-                        isRouteAdvertised =
-                            addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                        if (isRouteAdvertised) {
-                            subOpBuilder.setRouteAdvState(TaskState.Done);
-                        } else {
-                            subOpBuilder.setNhDpnId(null);
-                            subOpBuilder.setRouteAdvState(TaskState.Na);
-                        }
-                    } catch (Exception ex) {
-                        LOG.error(
-                            "onPortAddedToSubnet: Advertising NextHopDPN {} information for subnet {} to BGP failed",
-                            nhDpnId, subnetId.getValue(), ex);
+                if (subOpBuilder.getRouteAdvState() != TaskState.Advertised) {
+                    if (subOpBuilder.getNhDpnId() == null) {
+                        // No nexthop selected yet, elect one now
+                        electNewDpnForSubnetRoute(subOpBuilder, null /* oldDpnId */, subnetId,
+                                subnetmap.getNetworkId(), true);
+                    } else if (!VpnUtil.isExternalSubnetVpn(subnetOpDataEntry.getVpnName(), subnetId.getValue())) {
+                        // Already nexthop has been selected, only publishing to bgp required, so publish to bgp
+                        getNexthopTepAndPublishRoute(subOpBuilder, subnetId);
                     }
                 }
                 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                LOG.info("onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port {}",
-                    portId.getValue());
-
+                LOG.info("{} onPortAddedToSubnet: Updated subnetopdataentry to OP Datastore for port {} subnet {}"
+                        + " subnetIp {} vpnName {} rd {} TaskState {} lastTaskState {}", LOGGING_PREFIX,
+                        portId.getValue(), subnetId.getValue(), subOpEntry.getSubnetCidr(), subOpEntry.getVpnName(),
+                        subOpBuilder.getVrfId(), subOpEntry.getRouteAdvState(), subOpEntry.getLastAdvState());
             } catch (Exception ex) {
-                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} onPortAddedToSubnet: Updation of subnetOpEntry for port {} subnet {} falied {}",
+                        LOGGING_PREFIX, portId.getValue(), subnetId.getValue(), ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle port {} added to subnet {} {}", portId.getValue(), subnetId.getValue(), e);
+            LOG.error("{} onPortAddedToSubnet: Unable to handle port {} added to subnet {} {}", LOGGING_PREFIX,
+                    portId.getValue(), subnetId.getValue(), e);
         }
     }
 
@@ -469,10 +469,7 @@ public class VpnSubnetRouteHandler {
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void onPortRemovedFromSubnet(Subnetmap subnetmap, Uuid portId) {
         Uuid subnetId = subnetmap.getId();
-        boolean isRouteAdvertised = false;
 
-        LOG.info(
-            "onPortRemovedFromSubnet: Port " + portId.getValue() + " being removed from subnet " + subnetId.getValue());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -483,12 +480,11 @@ public class VpnSubnetRouteHandler {
                 }
                 BigInteger dpnId = portOpEntry.getDpnId();
                 if (dpnId == null) {
-                    LOG.debug("onPortRemovedFromSubnet:  Port {} does not have a DPNId associated, ignoring",
-                        portId.getValue());
+                    LOG.error("{} onPortRemovedFromSubnet:  Port {} does not have a DPNId associated,"
+                            + " ignoring removal from subnet {}", LOGGING_PREFIX, portId.getValue(),
+                            subnetId.getValue());
                     return;
                 }
-                LOG.debug(
-                    "onPortRemovedFromSubnet: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
                 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
@@ -496,109 +492,57 @@ public class VpnSubnetRouteHandler {
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.info("onPortRemovedFromSubnet: Port {} is part of a subnet {} that is not in VPN, ignoring",
-                        portId.getValue(), subnetId.getValue());
+                    LOG.info("{} onPortRemovedFromSubnet: Port {} is part of a subnet {} that is not in VPN,"
+                            + " ignoring", LOGGING_PREFIX, portId.getValue(), subnetId.getValue());
                     return;
                 }
-                SubnetOpDataEntry subOpEntry = null;
-                List<SubnetToDpn> subDpnList = null;
-                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
-                String rd = subOpBuilder.getVrfId();
-                String subnetIp = subOpBuilder.getSubnetCidr();
-                String vpnName = subOpBuilder.getVpnName();
-                Long elanTag = subOpBuilder.getElanTag();
+                LOG.info("{} onPortRemovedFromSubnet: Port {} being removed. Updating the SubnetOpDataEntry"
+                        + " for subnet {} subnetIp {} vpnName {} rd {} TaskState {} lastTaskState {}", LOGGING_PREFIX,
+                        portId.getValue(), subnetId.getValue(), optionalSubs.get().getSubnetCidr(),
+                        optionalSubs.get().getVpnName(), optionalSubs.get().getVrfId(),
+                        optionalSubs.get().getRouteAdvState(), optionalSubs.get().getLastAdvState());
+                SubnetOpDataEntry subnetOpDataEntry = optionalSubs.get();
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(subnetOpDataEntry);
                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
                     // select another NhDpnId
                     if (last) {
-                        LOG.debug("onPortRemovedFromSubnet: Last port {} on the subnet {}", portId,
-                            subnetId.getValue());
-                        // last port on this DPN, so we need to swap the NHDpnId
-                        subDpnList = subOpBuilder.getSubnetToDpn();
-                        if (subDpnList.isEmpty()) {
-                            subOpBuilder.setNhDpnId(null);
-                            try {
-                                // withdraw route from BGP
-                                deleteSubnetRouteFromFib(rd, subnetIp, vpnName, true /* isBgpVpn*/);
-                                subOpBuilder.setRouteAdvState(TaskState.Na);
-                            } catch (Exception ex) {
-                                LOG.error(
-                                    "onPortRemovedFromSubnet: Withdrawing NextHopDPN {} information for subnet {} "
-                                        + "from BGP failed ",
-                                    dpnId, subnetId.getValue(), ex);
-                                subOpBuilder.setRouteAdvState(TaskState.Pending);
-                            }
-                        } else {
-                            nhDpnId = subDpnList.get(0).getDpnId();
-                            subOpBuilder.setNhDpnId(nhDpnId);
-                            LOG.debug("onInterfaceDown: Swapping the Designated DPN to {} for subnet {}", nhDpnId,
-                                subnetId.getValue());
-                            try {
-                                // Best effort Withdrawal of route from BGP for this subnet
-                                // Advertise the new NexthopIP to BGP for this subnet
-                                //withdrawSubnetRoutefromBgp(rd, subnetIp);
-                                int label = getLabel(rd, subnetIp);
-                                if (label == 0) {
-                                    LOG.error(
-                                        "Unable to fetch label from Id Manager. Bailing out of handling removal of "
-                                            + "port {} from subnet {} in vpn {}",
-                                        portId.getValue(), subnetIp, vpnName);
-                                    return;
-                                }
-                                isRouteAdvertised =
-                                    addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                                if (isRouteAdvertised) {
-                                    subOpBuilder.setRouteAdvState(TaskState.Done);
-                                } else {
-                                    subOpBuilder.setNhDpnId(null);
-                                    subOpBuilder.setRouteAdvState(TaskState.Na);
-                                }
-                            } catch (Exception ex) {
-                                LOG.error(
-                                    "onPortRemovedFromSubnet: Swapping Withdrawing NextHopDPN {} information for "
-                                        + "subnet {} to BGP failed",
-                                    dpnId, subnetId.getValue(), ex);
-                                subOpBuilder.setRouteAdvState(TaskState.Pending);
-                            }
-                        }
+                        LOG.debug("{} onPortRemovedFromSubnet: Last port {} being removed from subnet {} subnetIp {}"
+                                + " vpnName {} rd {}", LOGGING_PREFIX, portId.getValue(), subnetId.getValue(),
+                                subOpBuilder.getSubnetCidr(), subOpBuilder.getVpnName(), subOpBuilder.getVrfId());
+                        // last port on this DPN, so we need to elect the new NHDpnId
+                        electNewDpnForSubnetRoute(subOpBuilder, nhDpnId, subnetId, subnetmap.getNetworkId(),
+                                !VpnUtil.isExternalSubnetVpn(subnetOpDataEntry.getVpnName(), subnetId.getValue()));
+                        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier,
+                                subOpBuilder.build());
+                        LOG.info("{} onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore"
+                                + " removing port {} from subnet {} subnetIp {} vpnName {} rd {}", LOGGING_PREFIX,
+                                portId.getValue(), subnetId.getValue(), subOpBuilder.getSubnetCidr(),
+                                subOpBuilder.getVpnName(), subOpBuilder.getVrfId());
                     }
                 }
-                subOpEntry = subOpBuilder.build();
-                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                LOG.info(
-                    "onPortRemovedFromSubnet: Updated subnetopdataentry to OP Datastore removing port " + portId
-                        .getValue());
             } catch (Exception ex) {
-                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} onPortRemovedFromSubnet: Removal of portOp for {} from subnet {} failed {}",
+                        LOGGING_PREFIX, portId.getValue(), subnetId.getValue(), ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle port {} removed from subnet {} {}", portId.getValue(), subnetId.getValue(),
-                e);
+            LOG.error("{} onPortRemovedFromSubnet: Unable to handle port {} removed from subnet {} {}",LOGGING_PREFIX,
+                    portId.getValue(), subnetId.getValue(), e);
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public void onInterfaceUp(BigInteger dpnId, String intfName) {
-        LOG.info("onInterfaceUp: Port " + intfName);
+    public void onInterfaceUp(BigInteger dpnId, String intfName, Uuid subnetId) {
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         SubnetToDpn subDpn = null;
-        boolean isRouteAdvertised = false;
-        PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(intfName);
-        if (portOpEntry == null) {
-            LOG.info("onInterfaceUp: Port " + intfName + "is part of a subnet not in VPN, ignoring");
+        if ((dpnId == null) || Objects.equals(dpnId, BigInteger.ZERO)) {
+            LOG.error("{} onInterfaceUp: Unable to determine the DPNID for port {} on subnet {}", LOGGING_PREFIX,
+                    intfName, subnetId.getValue());
             return;
         }
-        if ((dpnId == null) || (Objects.equals(dpnId, BigInteger.ZERO))) {
-            dpnId = portOpEntry.getDpnId();
-            if (dpnId == null) {
-                LOG.error("onInterfaceUp: Unable to determine the DPNID for port " + intfName);
-                return;
-            }
-        }
-        Uuid subnetId = portOpEntry.getSubnetId();
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
@@ -608,88 +552,65 @@ public class VpnSubnetRouteHandler {
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.error("onInterfaceUp: SubnetOpDataEntry for subnet {} is not available", subnetId.getValue());
+                    LOG.trace("{} onInterfaceUp: SubnetOpDataEntry for subnet {} is not available."
+                            + " Ignoring interfaceUp for port{}", LOGGING_PREFIX, subnetId.getValue(), intfName);
                     return;
                 }
-
-                LOG.debug("onInterfaceUp: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
                 subOpDpnManager.addPortOpDataEntry(intfName, subnetId, dpnId);
                 subDpn = subOpDpnManager.addInterfaceToDpn(subnetId, dpnId, intfName);
                 if (subDpn == null) {
                     return;
                 }
-                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
+                SubnetOpDataEntry subnetOpDataEntry = optionalSubs.get();
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(subnetOpDataEntry);
+                LOG.info("{} onInterfaceUp: Updating the SubnetOpDataEntry node for subnet {} subnetIp {} vpn {}"
+                        + " rd {} TaskState {} lastTaskState {}" , LOGGING_PREFIX, subnetId.getValue(),
+                        subOpBuilder.getSubnetCidr(), subOpBuilder.getVpnName(), subOpBuilder.getVrfId(),
+                        subOpBuilder.getRouteAdvState(), subOpBuilder.getLastAdvState());
+                boolean isExternalSubnetVpn = VpnUtil.isExternalSubnetVpn(subnetOpDataEntry.getVpnName(),
+                        subnetId.getValue());
                 List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
                 subDpnList.add(subDpn);
                 subOpBuilder.setSubnetToDpn(subDpnList);
-                if (subOpBuilder.getNhDpnId() == null) {
-                    subOpBuilder.setNhDpnId(dpnId);
-                }
-                BigInteger nhDpnId = subOpBuilder.getNhDpnId();
-                String rd = subOpBuilder.getVrfId();
-                String subnetIp = subOpBuilder.getSubnetCidr();
-                String vpnName = subOpBuilder.getVpnName();
-                Long elanTag = subOpBuilder.getElanTag();
-                if ((subOpBuilder.getRouteAdvState() == TaskState.Pending)
-                    || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
-                    try {
-                        // Write the Subnet Route Entry to FIB
-                        // Advertise BGP Route here and set route_adv_state to DONE
-                        int label = getLabel(rd, subnetIp);
-                        if (label == 0) {
-                            LOG.error(
-                                "Unable to fetch label from Id Manager. Bailing out of handling interface up event "
-                                    + "for port {} for subnet {} in vpn {}",
-                                intfName, subnetIp, vpnName);
-                            return;
-                        }
-                        isRouteAdvertised =
-                            addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                        if (isRouteAdvertised) {
-                            subOpBuilder.setRouteAdvState(TaskState.Done);
-                        } else {
-                            subOpBuilder.setNhDpnId(null);
-                            subOpBuilder.setRouteAdvState(TaskState.Na);
-                        }
-                    } catch (Exception ex) {
-                        LOG.error("onInterfaceUp: Advertising NextHopDPN {} information for subnet {} to BGP failed",
-                            nhDpnId, subnetId.getValue(), ex);
+                if (subOpBuilder.getRouteAdvState() != TaskState.Advertised) {
+                    if (subOpBuilder.getNhDpnId() == null) {
+                        // No nexthop selected yet, elect one now
+                        electNewDpnForSubnetRoute(subOpBuilder, null /* oldDpnId */, subnetId,
+                                null /*networkId*/, !isExternalSubnetVpn);
+                    } else if (!isExternalSubnetVpn) {
+                        // Already nexthop has been selected, only publishing to bgp required, so publish to bgp
+                        getNexthopTepAndPublishRoute(subOpBuilder, subnetId);
                     }
                 }
                 SubnetOpDataEntry subOpEntry = subOpBuilder.build();
                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                LOG.info("onInterfaceUp: Updated subnetopdataentry to OP Datastore port up " + intfName);
+                LOG.info("{} onInterfaceUp: Updated subnetopdataentry to OP Datastore port {} up for subnet {}"
+                        + " subnetIp {} vpnName {} rd {} TaskState {} lastTaskState {} ", LOGGING_PREFIX, intfName,
+                        subnetId.getValue(), subOpEntry.getSubnetCidr(), subOpEntry.getVpnName(),
+                        subOpEntry.getVrfId(), subOpEntry.getRouteAdvState(), subOpEntry.getLastAdvState());
             } catch (Exception ex) {
-                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} onInterfaceUp: Updation of SubnetOpDataEntry for subnet {} on port {} up failed {}",
+                        LOGGING_PREFIX, subnetId.getValue(), intfName, ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle interface up event for port {} in subnet {} {}", portOpEntry.getPortId(),
-                subnetId.getValue(), e);
+            LOG.error("{} onInterfaceUp: Unable to handle interface up event for port {} in subnet {} {}",
+                    LOGGING_PREFIX, intfName, subnetId.getValue(), e);
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    public void onInterfaceDown(final BigInteger dpnId, final String interfaceName) {
-        boolean isRouteAdvertised = false;
-        LOG.info("onInterfaceDown: Port " + interfaceName);
-        //TODO(vivek): Change this to use more granularized lock at subnetId level
-        PortOpDataEntry portOpEntry = subOpDpnManager.getPortOpDataEntry(interfaceName);
-        if (portOpEntry == null) {
-            LOG.info("onInterfaceDown: Port " + interfaceName + "is part of a subnet not in VPN, ignoring");
-            return;
-        }
+    public void onInterfaceDown(final BigInteger dpnId, final String interfaceName, Uuid subnetId) {
         if ((dpnId == null) || (Objects.equals(dpnId, BigInteger.ZERO))) {
-            LOG.error("onInterfaceDown: Unable to determine the DPNID for port " + interfaceName);
+            LOG.error("{} onInterfaceDown: Unable to determine the DPNID for port {} on subnet {}", LOGGING_PREFIX,
+                    interfaceName, subnetId.getValue());
             return;
         }
-        Uuid subnetId = portOpEntry.getSubnetId();
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
-                LOG.debug("onInterfaceDown: Updating the SubnetOpDataEntry node for subnet: " + subnetId.getValue());
                 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, interfaceName);
                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
@@ -698,91 +619,52 @@ public class VpnSubnetRouteHandler {
                     LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.error("onInterfaceDown: SubnetOpDataEntry for subnet {} is not available", subnetId.getValue());
+                    LOG.error("{} onInterfaceDown: SubnetOpDataEntry for subnet {} is not available."
+                            + " Ignoring port {} down event.", LOGGING_PREFIX, subnetId.getValue(), interfaceName);
                     return;
                 }
-                SubnetOpDataEntry subOpEntry = null;
-                List<SubnetToDpn> subDpnList = null;
-                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
-                String rd = subOpBuilder.getVrfId();
-                String subnetIp = subOpBuilder.getSubnetCidr();
-                String vpnName = subOpBuilder.getVpnName();
-                Long elanTag = subOpBuilder.getElanTag();
+                SubnetOpDataEntry subnetOpDataEntry = optionalSubs.get();
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(subnetOpDataEntry);
+                LOG.info("{} onInterfaceDown: Updating the SubnetOpDataEntry node for subnet {} subnetIp {}"
+                        + " vpnName {} rd {} TaskState {} lastTaskState {} on port {} down", LOGGING_PREFIX,
+                        subnetId.getValue(), subOpBuilder.getSubnetCidr(), subOpBuilder.getVpnName(),
+                        subOpBuilder.getVrfId(), subOpBuilder.getRouteAdvState(), subOpBuilder.getLastAdvState(),
+                        interfaceName);
                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
                     // select another NhDpnId
                     if (last) {
-                        LOG.debug(
-                            "onInterfaceDown: Last active port " + interfaceName + " on the subnet: " + subnetId
-                                .getValue());
-                        // last port on this DPN, so we need to swap the NHDpnId
-                        subDpnList = subOpBuilder.getSubnetToDpn();
-                        if (subDpnList.isEmpty()) {
-                            subOpBuilder.setNhDpnId(null);
-                            try {
-                                // Withdraw route from BGP for this subnet
-                                deleteSubnetRouteFromFib(rd, subnetIp, vpnName, true /* isBgpVpn*/);
-                                subOpBuilder.setRouteAdvState(TaskState.Na);
-                            } catch (Exception ex) {
-                                LOG.error(
-                                    "onInterfaceDown: Withdrawing NextHopDPN {} information for subnet {} from BGP "
-                                        + "failed",
-                                    dpnId, subnetId.getValue(), ex);
-                                subOpBuilder.setRouteAdvState(TaskState.Pending);
-                            }
-                        } else {
-                            nhDpnId = subDpnList.get(0).getDpnId();
-                            subOpBuilder.setNhDpnId(nhDpnId);
-                            LOG.debug(
-                                "onInterfaceDown: Swapping the Designated DPN to {} for subnet {}" , nhDpnId,
-                                    subnetId.getValue());
-                            try {
-                                // Best effort Withdrawal of route from BGP for this subnet
-                                //withdrawSubnetRoutefromBgp(rd, subnetIp);
-                                int label = getLabel(rd, subnetIp);
-                                if (label == 0) {
-                                    LOG.error(
-                                        "Unable to fetch label from Id Manager. Bailing out of handling interface "
-                                            + "down event for port {} in subnet {} for vpn {}",
-                                        interfaceName, subnetIp, vpnName);
-                                    return;
-                                }
-                                isRouteAdvertised =
-                                    addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                                if (isRouteAdvertised) {
-                                    subOpBuilder.setRouteAdvState(TaskState.Done);
-                                } else {
-                                    subOpBuilder.setNhDpnId(null);
-                                    subOpBuilder.setRouteAdvState(TaskState.Na);
-                                }
-                            } catch (Exception ex) {
-                                LOG.error(
-                                    "onInterfaceDown: Swapping Withdrawing NextHopDPN {} information for "
-                                        + "subnet {} to BGP failed", dpnId, subnetId.getValue(), ex);
-                                subOpBuilder.setRouteAdvState(TaskState.Pending);
-                            }
-                        }
+                        LOG.debug("{} onInterfaceDown: Last active port {} on the subnet {} subnetIp {} vpn {}"
+                                + " rd {}", LOGGING_PREFIX, interfaceName, subnetId.getValue(),
+                                subOpBuilder.getSubnetCidr(), subOpBuilder.getVpnName(), subOpBuilder.getVrfId());
+                        // last port on this DPN, so we need to elect the new NHDpnId
+                        electNewDpnForSubnetRoute(subOpBuilder, dpnId, subnetId, null /*networkId*/,
+                                !VpnUtil.isExternalSubnetVpn(subnetOpDataEntry.getVpnName(), subnetId.getValue()));
+                        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier,
+                                subOpBuilder.build());
+                        LOG.info("{} onInterfaceDown: Updated subnetopdataentry for subnet {} subnetIp {} vpnName {}"
+                                + " rd {} to OP Datastore on port {} down ", LOGGING_PREFIX, subnetId.getValue(),
+                                subOpBuilder.getSubnetCidr(), subOpBuilder.getVpnName(), subOpBuilder.getVrfId(),
+                                interfaceName);
                     }
                 }
-                subOpEntry = subOpBuilder.build();
-                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                LOG.info("onInterfaceDown: Updated subnetopdataentry to OP Datastore port down " + interfaceName);
             } catch (Exception ex) {
-                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} onInterfaceDown: SubnetOpDataEntry update on interface {} down event for subnet {}"
+                        + " falied {}", LOGGING_PREFIX, interfaceName, subnetId.getValue(), ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle interface down event for port {} in subnet {} {}", portOpEntry.getPortId(),
-                subnetId.getValue(), e);
+            LOG.error("{} onInterfaceDown: Unable to handle interface down event for port {} in subnet {} {}",
+                    LOGGING_PREFIX, interfaceName, subnetId.getValue(), e);
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void updateSubnetRouteOnTunnelUpEvent(Uuid subnetId, BigInteger dpnId) {
-        boolean isRouteAdvertised = false;
-        LOG.info("updateSubnetRouteOnTunnelUpEvent: Subnet {} Dpn {}", subnetId.getValue(), dpnId.toString());
+        LOG.info("{} updateSubnetRouteOnTunnelUpEvent: Subnet {} Dpn {}", LOGGING_PREFIX, subnetId.getValue(),
+                dpnId.toString());
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
@@ -793,57 +675,44 @@ public class VpnSubnetRouteHandler {
                     LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.error("updateSubnetRouteOnTunnelUpEvent: SubnetOpDataEntry for subnet {} is not available",
-                        subnetId.getValue());
+                    LOG.error("{} updateSubnetRouteOnTunnelUpEvent: SubnetOpDataEntry for subnet {} is not available",
+                            LOGGING_PREFIX, subnetId.getValue());
                     return;
                 }
-                SubnetOpDataEntry subOpEntry = null;
-                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
-                String rd = subOpBuilder.getVrfId();
-                String subnetIp = subOpBuilder.getSubnetCidr();
-                String vpnName = subOpBuilder.getVpnName();
-                List<SubnetToDpn> subDpnList = subOpBuilder.getSubnetToDpn();
-                long elanTag = subOpBuilder.getElanTag();
-                if ((subOpBuilder.getRouteAdvState() == TaskState.Pending)
-                    || (subOpBuilder.getRouteAdvState() == TaskState.Na)) {
-                    for (SubnetToDpn subDpn : subDpnList) {
-                        if (subDpn.getDpnId().equals(dpnId)) {
-                            if (subOpBuilder.getNhDpnId() == null) {
-                                try {
-                                    subOpBuilder.setNhDpnId(dpnId);
-                                    int label = getLabel(rd, subnetIp);
-                                    isRouteAdvertised =
-                                        addSubnetRouteToFib(rd, subnetIp, dpnId, vpnName, elanTag, label, subnetId);
-                                    if (isRouteAdvertised) {
-                                        subOpBuilder.setRouteAdvState(TaskState.Done);
-                                    } else {
-                                        subOpBuilder.setNhDpnId(null);
-                                        subOpBuilder.setRouteAdvState(TaskState.Na);
-                                    }
-                                } catch (Exception ex) {
-                                    LOG.error(
-                                        "updateSubnetRouteOnTunnelUpEvent: Advertising NextHopDPN {} information for "
-                                            + "subnet {} to BGP failed",
-                                        dpnId, subnetId.getValue(), ex);
-                                }
-                            }
-                        }
+                LOG.info("{} updateSubnetRouteOnTunnelUpEvent: Subnet {} subnetIp {} vpnName {} rd {} TaskState {}"
+                        + " lastTaskState {} Dpn {}", LOGGING_PREFIX, subnetId.getValue(),
+                        optionalSubs.get().getSubnetCidr(), optionalSubs.get().getVpnName(),
+                        optionalSubs.get().getVrfId(), optionalSubs.get().getRouteAdvState(),
+                        optionalSubs.get().getLastAdvState(), dpnId.toString());
+                SubnetOpDataEntry subOpEntry = optionalSubs.get();
+                SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(subOpEntry);
+                boolean isExternalSubnetVpn = VpnUtil.isExternalSubnetVpn(subOpEntry.getVpnName(), subnetId.getValue());
+                if (subOpBuilder.getRouteAdvState() != TaskState.Advertised) {
+                    if (subOpBuilder.getNhDpnId() == null) {
+                        // No nexthop selected yet, elect one now
+                        electNewDpnForSubnetRoute(subOpBuilder, null /* oldDpnId */, subnetId,
+                                null /*networkId*/, !isExternalSubnetVpn);
+                    } else if (!isExternalSubnetVpn) {
+                        // Already nexthop has been selected, only publishing to bgp required, so publish to bgp
+                        getNexthopTepAndPublishRoute(subOpBuilder, subnetId);
                     }
-                    subOpEntry = subOpBuilder.build();
-                    MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                    LOG.info(
-                        "updateSubnetRouteOnTunnelUpEvent: Updated subnetopdataentry to OP Datastore tunnel up on dpn"
-                            + " {} for subnet {}",
-                        dpnId.toString(), subnetId.getValue());
                 }
+                subOpEntry = subOpBuilder.build();
+                MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
+                LOG.info("{} updateSubnetRouteOnTunnelUpEvent: Updated subnetopdataentry to OP Datastore tunnel up"
+                        + " on dpn {} for subnet {} subnetIp {} vpnName {} rd {} TaskState {} lastTaskState {}",
+                        LOGGING_PREFIX, dpnId.toString(), subnetId.getValue(), subOpEntry.getSubnetCidr(),
+                        subOpEntry.getVpnName(), subOpEntry.getVrfId(), subOpEntry.getRouteAdvState(),
+                        subOpEntry.getLastAdvState());
             } catch (Exception ex) {
-                LOG.error("Creation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} updateSubnetRouteOnTunnelUpEvent: updating subnetRoute for subnet {} on dpn {}",
+                        LOGGING_PREFIX, subnetId.getValue(), dpnId.toString(), ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle tunnel up event for subnetId {} dpnId {}", subnetId.getValue(),
-                dpnId.toString());
+            LOG.error("{} updateSubnetRouteOnTunnelUpEvent: Unable to handle tunnel up event for subnetId {} dpnId {}"
+                    + " with exception {}", LOGGING_PREFIX, subnetId.getValue(), dpnId.toString(), e);
         }
     }
 
@@ -862,81 +731,116 @@ public class VpnSubnetRouteHandler {
                     LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
-                    LOG.error("updateSubnetRouteOnTunnelDownEvent: SubnetOpDataEntry for subnet {} is not available",
-                        subnetId.getValue());
+                    LOG.error("{} updateSubnetRouteOnTunnelDownEvent: SubnetOpDataEntry for subnet {}"
+                            + " is not available", LOGGING_PREFIX, subnetId.getValue());
                     return;
                 }
+                LOG.debug("{} updateSubnetRouteOnTunnelDownEvent: Dpn {} Subnet {} subnetIp {} vpnName {} rd {}"
+                        + " TaskState {} lastTaskState {}", LOGGING_PREFIX, dpnId.toString(), subnetId.getValue(),
+                        optionalSubs.get().getSubnetCidr(), optionalSubs.get().getVpnName(),
+                        optionalSubs.get().getVrfId(), optionalSubs.get().getRouteAdvState(),
+                        optionalSubs.get().getLastAdvState());
                 SubnetOpDataEntry subOpEntry = null;
                 SubnetOpDataEntryBuilder subOpBuilder = new SubnetOpDataEntryBuilder(optionalSubs.get());
                 BigInteger nhDpnId = subOpBuilder.getNhDpnId();
                 if ((nhDpnId != null) && (nhDpnId.equals(dpnId))) {
-                    electNewDPNForSubNetRoute(subOpBuilder, dpnId, subnetId);
+                    electNewDpnForSubnetRoute(subOpBuilder, dpnId, subnetId, null /*networkId*/, true);
                     subOpEntry = subOpBuilder.build();
                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier, subOpEntry);
-                    LOG.info(
-                        "updateSubnetRouteOnTunnelDownEvent: Updated subnetopdataentry to OP Datastore tunnnel down "
-                            + "on dpn {} for subnet {}",
-                        dpnId.toString(), subnetId.getValue());
+                    LOG.info("{} updateSubnetRouteOnTunnelDownEvent: Subnet {} Dpn {} subnetIp {} vpnName {} rd {}"
+                            + " TaskState {} lastTaskState {}", LOGGING_PREFIX, subnetId.getValue(), dpnId.toString(),
+                            optionalSubs.get().getSubnetCidr(), optionalSubs.get().getVpnName(),
+                            optionalSubs.get().getVrfId(), optionalSubs.get().getRouteAdvState(),
+                            optionalSubs.get().getLastAdvState());
                 }
             } catch (Exception ex) {
-                LOG.error("Updation of SubnetOpDataEntry for subnet {} failed", subnetId.getValue(), ex);
+                LOG.error("{} updateSubnetRouteOnTunnelDownEvent: Updation of SubnetOpDataEntry for subnet {}"
+                        + " on dpn {} failed {}", LOGGING_PREFIX, subnetId.getValue(), dpnId, ex);
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle tunnel down event for subnetId {} dpnId {}", subnetId.getValue(),
-                dpnId.toString());
+            LOG.error("{} updateSubnetRouteOnTunnelDownEvent: Unable to handle tunnel down event for subnetId {}"
+                    + " dpnId {} with exception {}", LOGGING_PREFIX, subnetId.getValue(), dpnId.toString(), e);
         }
     }
 
-    private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
-            Long elanTag, int label, Uuid subnetId) throws Exception {
-        return addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId,
-                true /* isBgpVpn*/, null /* networkId */);
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void publishSubnetRouteToBgp(SubnetOpDataEntryBuilder subOpBuilder, String nextHopIp) {
+        try {
+            //BGP manager will handle withdraw and advertise internally if prefix
+            //already exist
+            long label = 0;
+            long l3vni = 0;
+
+            VrfEntry.EncapType encapType =  VpnUtil.getEncapType(VpnUtil.isL3VpnOverVxLan(l3vni));
+            if (encapType.equals(VrfEntry.EncapType.Vxlan)) {
+                l3vni = subOpBuilder.getL3vni();
+            } else {
+                label = subOpBuilder.getLabel();
+            }
+            bgpManager.advertisePrefix(subOpBuilder.getVrfId(), null /*macAddress*/, subOpBuilder.getSubnetCidr(),
+                    Arrays.asList(nextHopIp), encapType,  label, l3vni,
+                    0 /*l2vni*/, null /*gatewayMacAddress*/);
+            subOpBuilder.setLastAdvState(subOpBuilder.getRouteAdvState()).setRouteAdvState(TaskState.Advertised);
+        } catch (Exception e) {
+            LOG.error("{} publishSubnetRouteToBgp: Subnet route not advertised for subnet {} subnetIp {} vpn {} rd {}"
+                    + " with dpnid {}", LOGGING_PREFIX, subOpBuilder.getSubnetId().getValue(),
+                    subOpBuilder.getSubnetCidr(), subOpBuilder.getVpnName(), subOpBuilder.getVrfId(), nextHopIp, e);
+        }
+    }
+
+    private void getNexthopTepAndPublishRoute(SubnetOpDataEntryBuilder subOpBuilder, Uuid subnetId) {
+        String nhTepIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker,
+                subOpBuilder.getNhDpnId());
+        if (nhTepIp != null) {
+            publishSubnetRouteToBgp(subOpBuilder, nhTepIp);
+        } else {
+            LOG.warn("Unable to find nexthopip for rd {} subnetroute subnetip {} for dpnid {}",
+                    subOpBuilder.getVrfId(), subOpBuilder.getSubnetCidr(),
+                    subOpBuilder.getNhDpnId().toString());
+            electNewDpnForSubnetRoute(subOpBuilder, null /* oldDpnId */, subnetId, null /*networkId*/, true);
+        }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
-        Long elanTag, int label, Uuid subnetId, boolean isBgpVpn, String networkName) throws Exception {
-
-        Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
-        Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
-        Preconditions.checkNotNull(vpnName, "vpnName cannot be null or empty!");
-        Preconditions.checkNotNull(elanTag, "elanTag cannot be null or empty!");
-
-        String nexthopIp = null;
+    private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String nextHopIp,
+                                        String vpnName, Long elanTag, long label, long l3vni,
+                                        Uuid subnetId, boolean isBgpVpn, String networkName) {
+
+        Preconditions.checkNotNull(rd,
+                LOGGING_PREFIX + " addSubnetRouteToFib: RouteDistinguisher cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp,
+                LOGGING_PREFIX + " addSubnetRouteToFib: SubnetRouteIp cannot be null or empty!");
+        Preconditions.checkNotNull(vpnName, LOGGING_PREFIX + " addSubnetRouteToFib: vpnName cannot be null or empty!");
+        Preconditions.checkNotNull(elanTag, LOGGING_PREFIX + " addSubnetRouteToFib: elanTag cannot be null or empty!");
+        Preconditions.checkNotNull(label, LOGGING_PREFIX + " addSubnetRouteToFib: label cannot be null or empty!");
+        VrfEntry.EncapType encapType = VpnUtil.getEncapType(VpnUtil.isL3VpnOverVxLan(l3vni));
+        VpnPopulator vpnPopulator = L3vpnRegistry.getRegisteredPopulator(encapType);
+        LOG.info("{} addSubnetRouteToFib: Adding SubnetRoute fib entry for vpnName {}, subnetIP {}, elanTag {}",
+                LOGGING_PREFIX, vpnName, subnetIp, elanTag);
+        L3vpnInput input = new L3vpnInput().setRouteOrigin(RouteOrigin.CONNECTED).setRd(rd).setVpnName(vpnName)
+                .setSubnetIp(subnetIp).setNextHopIp(nextHopIp).setL3vni(l3vni).setLabel(label).setElanTag(elanTag)
+                .setDpnId(nhDpnId).setEncapType(encapType).setNetworkName(networkName).setPrimaryRd(rd);
         if (!isBgpVpn) {
-            LOG.info("Adding SubnetRoute fib entry for vpnName {}, subnetIP {}, elanTag {}",
-                    vpnName, subnetIp, elanTag);
-            vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId,
-                    networkName, null /* WriteTransaction */);
+            vpnPopulator.populateFib(input, null /*writeCfgTxn*/, null /*writeOperTxn*/);
             return true;
         }
-
+        Preconditions.checkNotNull(nextHopIp, LOGGING_PREFIX + "NextHopIp cannot be null or empty!");
+        VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, VpnUtil
+                .getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp), VpnUtil
+                .getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp, subnetId,
+                        Prefixes.PrefixCue.SubnetRoute));
+        vpnPopulator.populateFib(input, null /*writeCfgTxn*/, null /*writeOperTxn*/);
         try {
-            nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId);
+            // BGP manager will handle withdraw and advertise internally if prefix
+            // already exist
+            bgpManager.advertisePrefix(rd, null /*macAddress*/, subnetIp, Collections.singletonList(nextHopIp),
+                    encapType, label, l3vni, 0 /*l2vni*/, null /*gatewayMacAddress*/);
         } catch (Exception e) {
-            LOG.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp);
-            return false;
-        }
-        if (nexthopIp != null) {
-            VpnUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                VpnUtil.getPrefixToInterfaceIdentifier(VpnUtil.getVpnId(dataBroker, vpnName), subnetIp),
-                VpnUtil.getPrefixToInterface(nhDpnId, subnetId.getValue(), subnetIp, subnetId, true /* isNatPrefix*/));
-            vpnInterfaceManager.addSubnetRouteFibEntryToDS(rd, vpnName, subnetIp, nexthopIp, label, elanTag, nhDpnId,
-                    networkName, null);
-            try {
-                // BGP manager will handle withdraw and advertise internally if prefix
-                // already exist
-                bgpManager.advertisePrefix(rd, null /*macAddress*/, subnetIp, Collections.singletonList(nexthopIp),
-                        VrfEntry.EncapType.Mplsgre, label, 0 /*l3vni*/, 0 /*l2vni*/, null /*gatewayMacAddress*/);
-            } catch (Exception e) {
-                LOG.error("Fail: Subnet route not advertised for rd {} subnetIp {}", rd, subnetIp, e);
-                throw e;
-            }
-        } else {
-            LOG.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp);
+            LOG.error("{} addSubnetRouteToFib: Subnet route not advertised for subnet {} subnetIp {} vpnName {} rd {} "
+                    + "with dpnid {}", LOGGING_PREFIX, subnetId.getValue(), subnetIp, vpnName, rd, nhDpnId, e);
             return false;
         }
         return true;
@@ -945,30 +849,35 @@ public class VpnSubnetRouteHandler {
     private int getLabel(String rd, String subnetIp) {
         int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
             VpnUtil.getNextHopLabelKey(rd, subnetIp));
-        LOG.trace("Allocated subnetroute label {} for rd {} prefix {}", label, rd, subnetIp);
+        LOG.trace("{} getLabel: Allocated subnetroute label {} for rd {} prefix {}", LOGGING_PREFIX, label, rd,
+                subnetIp);
         return label;
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName, boolean isBgpVpn)
-            throws Exception {
-        Preconditions.checkNotNull(rd, "RouteDistinguisher cannot be null or empty!");
-        Preconditions.checkNotNull(subnetIp, "SubnetRouteIp cannot be null or empty!");
+    private boolean deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName, boolean isBgpVpn) {
+        Preconditions.checkNotNull(rd,
+                LOGGING_PREFIX + " deleteSubnetRouteFromFib: RouteDistinguisher cannot be null or empty!");
+        Preconditions.checkNotNull(subnetIp,
+                LOGGING_PREFIX +  " deleteSubnetRouteFromFib: SubnetRouteIp cannot be null or empty!");
         vpnInterfaceManager.deleteSubnetRouteFibEntryFromDS(rd, subnetIp, vpnName);
         if (isBgpVpn) {
             try {
                 bgpManager.withdrawPrefix(rd, subnetIp);
             } catch (Exception e) {
-                LOG.error("Fail: Subnet route not withdrawn for rd {} subnetIp {}", rd, subnetIp, e);
-                throw e;
+                LOG.error("{} deleteSubnetRouteFromFib: Subnet route not withdrawn for subnetIp {} vpn {} rd {}"
+                        + "  due to exception {}", LOGGING_PREFIX, subnetIp, vpnName, rd, e);
+                return false;
             }
         }
+        return true;
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void electNewDPNForSubNetRoute(SubnetOpDataEntryBuilder subOpBuilder, BigInteger dpnId, Uuid subnetId) {
+    private void electNewDpnForSubnetRoute(SubnetOpDataEntryBuilder subOpBuilder, BigInteger oldDpnId, Uuid subnetId,
+                                           Uuid networkId, boolean isBgpVpn) {
         List<SubnetToDpn> subDpnList = null;
         boolean isRouteAdvertised = false;
         subDpnList = subOpBuilder.getSubnetToDpn();
@@ -977,48 +886,98 @@ public class VpnSubnetRouteHandler {
         String vpnName = subOpBuilder.getVpnName();
         long elanTag = subOpBuilder.getElanTag();
         BigInteger nhDpnId = null;
+        String nhTepIp = null;
         boolean isAlternateDpnSelected = false;
-        Iterator<SubnetToDpn> subNetIt = subDpnList.iterator();
-        int label = getLabel(rd, subnetIp);
-        while (subNetIt.hasNext()) {
-            SubnetToDpn subnetToDpn = subNetIt.next();
+        long l3vni = 0;
+        long label = 0;
+        if (VpnUtil.isL3VpnOverVxLan(subOpBuilder.getL3vni())) {
+            l3vni = subOpBuilder.getL3vni();
+        } else {
+            label = getLabel(rd, subnetIp);
+            subOpBuilder.setLabel(label);
+        }
+        LOG.info("{} electNewDpnForSubnetRoute: Handling subnet {} subnetIp {} vpn {} rd {} TaskState {}"
+                + " lastTaskState {}", LOGGING_PREFIX, subnetId.getValue(), subnetIp, subOpBuilder.getVpnName(),
+                subOpBuilder.getVrfId(), subOpBuilder.getRouteAdvState(), subOpBuilder.getLastAdvState());
+        if (!isBgpVpn) {
+            // Non-BGPVPN as it stands here represents use-case of External Subnets of VLAN-Provider-Network
+            //  TODO(Tomer):  Pulling in both external and internal VLAN-Provider-Network need to be
+            // blended more better into this design.
+            isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, nhTepIp,
+                    vpnName, elanTag, label, l3vni, subnetId, isBgpVpn, networkId.getValue());
+            if (isRouteAdvertised) {
+                subOpBuilder.setRouteAdvState(TaskState.Advertised);
+            } else {
+                LOG.error("{} electNewDpnForSubnetRoute: Unable to find TepIp for subnet {} subnetip {} vpnName {}"
+                    + " rd {} for dpnid {}, attempt next dpn", LOGGING_PREFIX, subnetId.getValue(), subnetIp,
+                    vpnName, rd, nhDpnId.toString());
+                subOpBuilder.setRouteAdvState(TaskState.PendingAdvertise);
+            }
+            return;
+        }
+        Iterator<SubnetToDpn> subnetDpnIter = subDpnList.iterator();
+        while (subnetDpnIter.hasNext()) {
+            SubnetToDpn subnetToDpn = subnetDpnIter.next();
+            if (subnetToDpn.getDpnId().equals(oldDpnId)) {
+                // Is this same is as input dpnId, then ignore it
+                continue;
+            }
             nhDpnId = subnetToDpn.getDpnId();
-            if (!nhDpnId.equals(dpnId)) {
+            if (vpnNodeListener.isConnectedNode(nhDpnId)) {
+                // selected dpnId is connected to ODL
+                // but does it have a TEP configured at all?
                 try {
-                    //update the VRF entry for the subnetroute.
-                    isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, vpnName, elanTag, label, subnetId);
-                    if (isRouteAdvertised) {
-                        subOpBuilder.setRouteAdvState(TaskState.Done);
-                        subOpBuilder.setNhDpnId(nhDpnId);
+                    nhTepIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId);
+                    if (nhTepIp != null) {
                         isAlternateDpnSelected = true;
                         break;
                     }
-                } catch (Exception ex) {
-                    LOG.error(
-                        "electNewDPNForSubNetRoute: Swapping and trying to configure NextHopDPN {} for subnet {} "
-                            + "failed ex {}",
-                        dpnId.toString(), subnetId.getValue(), ex);
-                    subOpBuilder.setRouteAdvState(TaskState.Na);
+                } catch (Exception e) {
+                    LOG.warn("{} electNewDpnForSubnetRoute: Unable to find TepIp for rd {} subnetroute subnetip {}"
+                            + " for dpnid {}, attempt next", LOGGING_PREFIX, rd, subnetIp, nhDpnId.toString(), e);
+                    continue;
                 }
             }
         }
-
-        //If no alternate Dpn is selected as nextHopDpn ,withdraw the subnetroute.
         if (!isAlternateDpnSelected) {
-            LOG.info("No alternate DPN available for subnet {}.Prefix withdrawn from BGP", subnetIp);
-            try {
+            //If no alternate Dpn is selected as nextHopDpn, withdraw the subnetroute if it had a nextHop already.
+            if (isRouteAdvertised(subOpBuilder) && (oldDpnId != null)) {
+                LOG.info("{} electNewDpnForSubnetRoute: No alternate DPN available for subnet {} subnetIp {} vpn {}"
+                        + " rd {} Prefix withdrawn from BGP", LOGGING_PREFIX, subnetId.getValue(), subnetIp, vpnName,
+                        rd);
                 // Withdraw route from BGP for this subnet
-                deleteSubnetRouteFromFib(rd, subnetIp, vpnName, true /* isBgpVpn*/);
+                boolean routeWithdrawn = deleteSubnetRouteFromFib(rd, subnetIp, vpnName, isBgpVpn);
                 subOpBuilder.setNhDpnId(null);
-                subOpBuilder.setRouteAdvState(TaskState.Na);
-            } catch (Exception ex) {
-                LOG.error(
-                    "electNewDPNForSubNetRoute: Withdrawing NextHopDPN " + dpnId.toString() + " information for subnet "
-                        +
-                        subnetId.getValue() + " from BGP failed {}" + ex);
-                subOpBuilder.setRouteAdvState(TaskState.Pending);
+                subOpBuilder.setLastAdvState(subOpBuilder.getRouteAdvState());
+                if (routeWithdrawn) {
+                    subOpBuilder.setRouteAdvState(TaskState.Withdrawn);
+                } else {
+                    LOG.error("{} electNewDpnForSubnetRoute: Withdrawing NextHopDPN {} for subnet {} subnetIp {}"
+                        + " vpn {} rd {} from BGP failed", LOGGING_PREFIX, oldDpnId.toString(), subnetId.getValue(),
+                        subnetIp, vpnName, rd);
+                    subOpBuilder.setRouteAdvState(TaskState.PendingWithdraw);
+                }
+            }
+        } else {
+            //If alternate Dpn is selected as nextHopDpn, use that for subnetroute.
+            subOpBuilder.setNhDpnId(nhDpnId);
+            //update the VRF entry for the subnetroute.
+            isRouteAdvertised = addSubnetRouteToFib(rd, subnetIp, nhDpnId, nhTepIp,
+                    vpnName, elanTag, label, l3vni, subnetId, isBgpVpn, networkId.getValue());
+            subOpBuilder.setLastAdvState(subOpBuilder.getRouteAdvState());
+            if (isRouteAdvertised) {
+                subOpBuilder.setRouteAdvState(TaskState.Advertised);
+            } else {
+                LOG.error("{} electNewDpnForSubnetRoute: Swapping to add new NextHopDpn {} for subnet {} subnetIp {}"
+                        + " vpn {} rd {} failed", LOGGING_PREFIX, nhDpnId, subnetId.getValue(), subnetIp, vpnName, rd);
+                subOpBuilder.setRouteAdvState(TaskState.PendingAdvertise);
             }
         }
     }
+
+    private boolean isRouteAdvertised(SubnetOpDataEntryBuilder subOpBuilder) {
+        return ((subOpBuilder.getRouteAdvState() == TaskState.Advertised)
+                || (subOpBuilder.getRouteAdvState() == TaskState.PendingAdvertise));
+    }
 }