Lower log levels for non error's
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / VpnSubnetRouteHandler.java
index e538de71cf24cb5a3c06889f9b4569caee281c54..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 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;
 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.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.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;
 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.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;
 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;
@@ -41,16 +47,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.sub
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NeutronvpnListener;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortAddedToSubnet;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.PortRemovedFromSubnet;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterAssociatedToVpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.RouterDisassociatedFromVpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetAddedToVpnBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpn;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetDeletedFromVpnBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.SubnetUpdatedInVpn;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
@@ -58,8 +54,9 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class VpnSubnetRouteHandler implements NeutronvpnListener {
+public class VpnSubnetRouteHandler {
     private static final Logger LOG = LoggerFactory.getLogger(VpnSubnetRouteHandler.class);
     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;
     private final DataBroker dataBroker;
     private final SubnetOpDpnManager subOpDpnManager;
     private final IBgpManager bgpManager;
@@ -67,10 +64,12 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     private final IdManagerService idManager;
     private LockManagerService lockManager;
     private final VpnOpDataSyncer vpnOpDataSyncer;
     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,
 
     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;
         this.dataBroker = dataBroker;
         this.subOpDpnManager = subnetOpDpnManager;
         this.bgpManager = bgpManager;
@@ -78,45 +77,52 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         this.idManager = idManager;
         this.lockManager = lockManagerService;
         this.vpnOpDataSyncer = vpnOpDataSyncer;
         this.idManager = idManager;
         this.lockManager = lockManagerService;
         this.vpnOpDataSyncer = vpnOpDataSyncer;
+        this.vpnNodeListener = vpnNodeListener;
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    @Override
-    public void onSubnetAddedToVpn(SubnetAddedToVpn notification) {
-        if (!notification.isBgpVpn()) {
-            return;
-        }
-
-        Uuid subnetId = notification.getSubnetId();
-        String vpnName = notification.getVpnName();
-        String subnetIp = notification.getSubnetIp();
-        Long elanTag = notification.getElanTag();
-        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);
+    public void onSubnetAddedToVpn(Subnetmap subnetmap, boolean isBgpVpn, Long elanTag) {
+        Uuid subnetId = subnetmap.getId();
+        String subnetIp = subnetmap.getSubnetIp();
+        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) {
             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 {
         //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 =
 
                 // Please check if subnetId belongs to an External Network
                 InstanceIdentifier<Subnetmap> subMapid =
@@ -124,86 +130,105 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                         new SubnetmapKey(subnetId)).build();
                 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
                 if (!sm.isPresent()) {
                         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();
                     return;
                 }
                 subMap = sm.get();
-                InstanceIdentifier<Networks> netsIdentifier =
-                    InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
-                        new NetworksKey(subMap.getNetworkId())).build();
-                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());
-                    return;
+
+                if (isBgpVpn) {
+                    InstanceIdentifier<Networks> netsIdentifier = InstanceIdentifier.builder(ExternalNetworks.class)
+                            .child(Networks.class, new NetworksKey(subMap.getNetworkId())).build();
+                    Optional<Networks> optionalNets = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
+                            netsIdentifier);
+                    if (optionalNets.isPresent()) {
+                        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
                 }
                 //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();
                         new SubnetOpDataEntryKey(subnetId)).build();
-                Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker,
-                        LogicalDatastoreType.OPERATIONAL,
-                        subOpIdentifier);
+                optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
                 if (optionalSubs.isPresent()) {
                 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;
                 }
                     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);
                 subOpBuilder.setSubnetId(subnetId);
                 subOpBuilder.setSubnetCidr(subnetIp);
                 String primaryRd = VpnUtil.getPrimaryRd(dataBroker, vpnName);
-                if (!VpnUtil.isBgpVpn(vpnName, primaryRd)) {
-                    LOG.error("onSubnetAddedToVpn: The VPN Instance name "
-                            + notification.getVpnName() + " does not have RD ");
+
+                if (isBgpVpn && !VpnUtil.isBgpVpn(vpnName, primaryRd)) {
+                    LOG.error("{} onSubnetAddedToVpn: The VPN Instance name {} does not have RD. Bailing out for"
+                            + " subnet {} subnetIp {} ", LOGGING_PREFIX, vpnName, subnetId.getValue(), subnetIp);
                     return;
                 }
                     return;
                 }
+
                 subOpBuilder.setVrfId(primaryRd);
                 subOpBuilder.setVpnName(vpnName);
                 subOpBuilder.setSubnetToDpn(new ArrayList<>());
                 subOpBuilder.setVrfId(primaryRd);
                 subOpBuilder.setVpnName(vpnName);
                 subOpBuilder.setSubnetToDpn(new ArrayList<>());
-                subOpBuilder.setRouteAdvState(TaskState.Na);
+                subOpBuilder.setRouteAdvState(TaskState.Idle);
                 subOpBuilder.setElanTag(elanTag);
                 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());
+            }
 
 
-                // First recover set of ports available in this subnet
+            //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>();
+
+                optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
+                subOpBuilder =
+                        new SubnetOpDataEntryBuilder(optionalSubs.get()).setKey(new SubnetOpDataEntryKey(subnetId));
                 List<Uuid> portList = subMap.getPortList();
                 if (portList != null) {
                 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) {
                         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)) {
                                 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) {
                                 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);
                                 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);
                             }
                         } else {
                             subOpDpnManager.addPortOpDataEntry(port.getValue(), subnetId, null);
@@ -213,67 +238,32 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                         subOpBuilder.setSubnetToDpn(new ArrayList<>(subDpnMap.values()));
                     }
                 }
                         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);
-                        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 {
-                    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) {
             } 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) {
             } 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);
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    @Override
-    public void onSubnetDeletedFromVpn(SubnetDeletedFromVpn notification) {
-        Uuid subnetId = notification.getSubnetId();
-
-        if (!notification.isBgpVpn()) {
-            return;
-        }
-        LOG.info("onSubnetDeletedFromVpn: Subnet " + subnetId.getValue() + " being removed from vpn");
+    public void onSubnetDeletedFromVpn(Subnetmap subnetmap, boolean isBgpVpn) {
+        Uuid subnetId = subnetmap.getId();
+        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());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -281,16 +271,19 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
                         new SubnetOpDataEntryKey(subnetId)).build();
                 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()) {
                 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;
                 }
                     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
                 /* 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
@@ -301,7 +294,9 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                         new SubnetmapKey(subnetId)).build();
                 Optional<Subnetmap> sm = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, subMapid);
                 if (!sm.isPresent()) {
                         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();
                 } else {
                     Subnetmap subMap = sm.get();
                     List<Uuid> portList = subMap.getPortList();
@@ -310,7 +305,11 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                             InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
                                 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
                                     new PortOpDataEntryKey(port.getValue())).build();
                             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);
                         }
                     }
                             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
                         }
                     }
@@ -320,40 +319,37 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 String rd = subOpBuilder.getVrfId();
                 String subnetIp = subOpBuilder.getSubnetCidr();
                 String vpnName = subOpBuilder.getVpnName();
                 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);
                 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);
-                } 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) {
             } 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) {
             } finally {
                 VpnUtil.unlockSubnet(lockManager, subnetId.getValue());
             }
         } catch (Exception e) {
-            LOG.error("Unable to handle subnet {} removed to vpn {}", notification.getSubnetIp(),
-                notification.getVpnName(), e);
+            LOG.error("{} onSubnetDeletedFromVpn: Unable to handle subnet {} with Ip {} removed from vpn {} {}",
+                    LOGGING_PREFIX, subnetId.getValue(), subnetmap.getSubnetIp(), subnetmap.getVpnId(), e);
         }
     }
 
         }
     }
 
-    @Override
-    public void onSubnetUpdatedInVpn(SubnetUpdatedInVpn notification) {
-        Uuid subnetId = notification.getSubnetId();
-        String vpnName = notification.getVpnName();
-        String subnetIp = notification.getSubnetIp();
-        Long elanTag = notification.getElanTag();
+    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,
 
         InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
             InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
@@ -361,31 +357,20 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         Optional<SubnetOpDataEntry> optionalSubs =
             VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
         if (optionalSubs.isPresent()) {
         Optional<SubnetOpDataEntry> optionalSubs =
             VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, subOpIdentifier);
         if (optionalSubs.isPresent()) {
-            if (!notification.isBgpVpn()) {
-                SubnetDeletedFromVpnBuilder bldr = new SubnetDeletedFromVpnBuilder().setVpnName(vpnName);
-                bldr.setElanTag(elanTag).setBgpVpn(true).setSubnetIp(subnetIp).setSubnetId(subnetId);
-                onSubnetDeletedFromVpn(bldr.build());
-            }
-            // TODO(vivek): Something got updated, but we donot know what ?
+            onSubnetDeletedFromVpn(subnetmap, true);
         } else {
         } else {
-            if (notification.isBgpVpn()) {
-                SubnetAddedToVpnBuilder bldr = new SubnetAddedToVpnBuilder().setVpnName(vpnName).setElanTag(elanTag);
-                bldr.setSubnetIp(subnetIp).setSubnetId(subnetId).setBgpVpn(true);
-                onSubnetAddedToVpn(bldr.build());
-            }
-            // 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")
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    @Override
-    public void onPortAddedToSubnet(PortAddedToSubnet notification) {
-        Uuid subnetId = notification.getSubnetId();
-        Uuid portId = notification.getPortId();
-        boolean isRouteAdvertised = false;
-
-        LOG.info("onPortAddedToSubnet: Port " + portId.getValue() + " being added to subnet " + subnetId.getValue());
+    public void onPortAddedToSubnet(Subnetmap subnetmap, Uuid portId) {
+        Uuid subnetId = subnetmap.getId();
+        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());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -397,104 +382,94 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                         subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
                 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;
                 }
                     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
                 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) {
                     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)) {
                     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) {
                     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;
                 }
                     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) {
                 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;
                 }
                     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);
                 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);
                     }
                 }
                 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) {
             } 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) {
             } 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);
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
         }
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    @Override
-    public void onPortRemovedFromSubnet(PortRemovedFromSubnet notification) {
-        Uuid subnetId = notification.getSubnetId();
-        Uuid portId = notification.getPortId();
-        boolean isRouteAdvertised = false;
+    public void onPortRemovedFromSubnet(Subnetmap subnetmap, Uuid portId) {
+        Uuid subnetId = subnetmap.getId();
 
 
-        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());
         //TODO(vivek): Change this to use more granularized lock at subnetId level
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
@@ -505,12 +480,11 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 }
                 BigInteger dpnId = portOpEntry.getDpnId();
                 if (dpnId == null) {
                 }
                 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;
                 }
                     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,
                 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, portId.getValue());
                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
@@ -518,109 +492,57 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
                 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;
                 }
                     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) {
                 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);
-                                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) {
             } 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) {
             } 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")
         }
     }
 
     // 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;
         //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;
         }
             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 {
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
@@ -630,88 +552,65 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                 Optional<SubnetOpDataEntry> optionalSubs = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
                 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;
                 }
                     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;
                 }
                 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);
                 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);
                     }
                 }
                 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) {
             } 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) {
             } 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")
         }
     }
 
     // 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))) {
         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;
         }
             return;
         }
-        Uuid subnetId = portOpEntry.getSubnetId();
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
         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,
                 boolean last = subOpDpnManager.removeInterfaceFromDpn(subnetId, dpnId, interfaceName);
                 InstanceIdentifier<SubnetOpDataEntry> subOpIdentifier =
                     InstanceIdentifier.builder(SubnetOpData.class).child(SubnetOpDataEntry.class,
@@ -720,99 +619,52 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                     LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
                     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;
                 }
                     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) {
                 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);
-                                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) {
             } 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) {
             } 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);
         }
     }
 
         }
     }
 
-    @Override
-    public void onRouterAssociatedToVpn(RouterAssociatedToVpn notification) {
-    }
-
-    @Override
-    public void onRouterDisassociatedFromVpn(RouterDisassociatedFromVpn notification) {
-    }
-
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     public void updateSubnetRouteOnTunnelUpEvent(Uuid subnetId, BigInteger dpnId) {
     // 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 {
         try {
             VpnUtil.lockSubnet(lockManager, subnetId.getValue());
             try {
@@ -823,57 +675,44 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                     LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
                     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;
                 }
                     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) {
             } 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) {
             } 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);
         }
     }
 
         }
     }
 
@@ -892,65 +731,116 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
                     LogicalDatastoreType.OPERATIONAL,
                     subOpIdentifier);
                 if (!optionalSubs.isPresent()) {
                     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;
                 }
                     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))) {
                 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);
                     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) {
                 }
             } 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) {
             } 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);
         }
     }
 
         }
     }
 
-    // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private boolean addSubnetRouteToFib(String rd, String subnetIp, BigInteger nhDpnId, String vpnName,
-        Long elanTag, int label, Uuid subnetId) 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 void publishSubnetRouteToBgp(SubnetOpDataEntryBuilder subOpBuilder, String nextHopIp) {
         try {
         try {
-            nexthopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, nhDpnId);
+            //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) {
         } catch (Exception e) {
-            LOG.warn("Unable to find nexthopip for subnetroute subnetip {}", subnetIp);
-            return false;
+            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);
         }
         }
-        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,
-                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;
-            }
+    }
+
+    private void getNexthopTepAndPublishRoute(SubnetOpDataEntryBuilder subOpBuilder, Uuid subnetId) {
+        String nhTepIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker,
+                subOpBuilder.getNhDpnId());
+        if (nhTepIp != null) {
+            publishSubnetRouteToBgp(subOpBuilder, nhTepIp);
         } else {
         } else {
-            LOG.warn("The nexthopip is empty for subnetroute subnetip {}, ignoring fib route addition", subnetIp);
+            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 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) {
+            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 {
+            // 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.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;
             return false;
         }
         return true;
@@ -959,27 +849,35 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
     private int getLabel(String rd, String subnetIp) {
         int label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
             VpnUtil.getNextHopLabelKey(rd, subnetIp));
     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")
         return label;
     }
 
     // TODO Clean up the exception handling
     @SuppressWarnings("checkstyle:IllegalCatch")
-    private void deleteSubnetRouteFromFib(String rd, String subnetIp, String vpnName) 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);
         vpnInterfaceManager.deleteSubnetRouteFibEntryFromDS(rd, subnetIp, vpnName);
-        try {
-            bgpManager.withdrawPrefix(rd, subnetIp);
-        } catch (Exception e) {
-            LOG.error("Fail: Subnet route not withdrawn for rd {} subnetIp {}", rd, subnetIp, e);
-            throw e;
+        if (isBgpVpn) {
+            try {
+                bgpManager.withdrawPrefix(rd, subnetIp);
+            } catch (Exception 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")
     }
 
     // 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();
         List<SubnetToDpn> subDpnList = null;
         boolean isRouteAdvertised = false;
         subDpnList = subOpBuilder.getSubnetToDpn();
@@ -988,48 +886,98 @@ public class VpnSubnetRouteHandler implements NeutronvpnListener {
         String vpnName = subOpBuilder.getVpnName();
         long elanTag = subOpBuilder.getElanTag();
         BigInteger nhDpnId = null;
         String vpnName = subOpBuilder.getVpnName();
         long elanTag = subOpBuilder.getElanTag();
         BigInteger nhDpnId = null;
+        String nhTepIp = null;
         boolean isAlternateDpnSelected = false;
         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();
             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 {
                 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;
                     }
                         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) {
         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
                 // Withdraw route from BGP for this subnet
-                deleteSubnetRouteFromFib(rd, subnetIp, vpnName);
+                boolean routeWithdrawn = deleteSubnetRouteFromFib(rd, subnetIp, vpnName, isBgpVpn);
                 subOpBuilder.setNhDpnId(null);
                 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));
+    }
 }
 
 }