BUG 6489: Routes to InterVpnLink not advertised on BGP
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / InterVpnLinkListener.java
index a41480542d8218ab23457180bc2de448a61ebfd7..6ac8d8427017584851585ab8331e3082d542cc6e 100644 (file)
@@ -7,11 +7,16 @@
  */
 package org.opendaylight.netvirt.vpnmanager.intervpnlink;
 
-
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
@@ -24,7 +29,7 @@ import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.NwConstants;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
-import org.opendaylight.netvirt.bgpmanager.api.RouteOrigin;
+import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
@@ -32,7 +37,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.Fl
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkCreationError;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.netvirt.inter.vpn.link.rev160311.InterVpnLinkCreationErrorBuilder;
@@ -53,70 +63,47 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.math.BigInteger;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLink> {
-    private static final Logger logger = LoggerFactory.getLogger(InterVpnLinkListener.class);
-    private static final String NBR_OF_DPNS_PROPERTY_NAME = "vpnservice.intervpnlink.number.dpns";
-    private static final int INVALID_ID = 0;
-
-    private IMdsalApiManager mdsalManager;
-    private IdManagerService idManager;
-    private IBgpManager bgpManager;
-    private NotificationPublishService notificationsService;
-
+public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLink> implements  AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(InterVpnLinkListener.class);
     private ListenerRegistration<DataChangeListener> listenerRegistration;
-    private final DataBroker broker;
-
+    private final DataBroker dataBroker;
+    private final IMdsalApiManager mdsalManager;
+    private final IdManagerService idManager;
+    private final IBgpManager bgpManager;
+    private final NotificationPublishService notificationsService;
+    private static final String NBR_OF_DPNS_PROPERTY_NAME = "vpnservice.intervpnlink.number.dpns";
+    private static final long INVALID_ID = 0;
 
-    public InterVpnLinkListener(DataBroker db, IdManagerService idManager, IMdsalApiManager mdsalManager,
-                                IBgpManager bgpManager, NotificationPublishService notifService) {
+    public InterVpnLinkListener(final DataBroker dataBroker, final IdManagerService idManager,
+                                final IMdsalApiManager mdsalManager, final IBgpManager bgpManager,
+                                final NotificationPublishService notifService) {
         super(InterVpnLink.class);
-        this.broker = db;
+        this.dataBroker = dataBroker;
         this.idManager = idManager;
         this.mdsalManager = mdsalManager;
         this.bgpManager = bgpManager;
         this.notificationsService = notifService;
-        this.registerListener(db);
     }
 
-    public void close() {
-        if (listenerRegistration != null) {
-            try {
-                listenerRegistration.close();
-            } catch (final Exception e) {
-                logger.error("Error when cleaning up DataChangeListener.", e);
-            }
-            listenerRegistration = null;
-        }
-    }
-
-
-    /**
-     * Register the databroker to all the possible changes from MDSAL - InterVpnLink class
-     *
-     * @param db dataBroker service reference
-     */
-    private void registerListener(DataBroker db) {
-        try {
-            this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                                                                      this.getWildCardPath(),
-                                                                      this,
-                                                                      AsyncDataBroker.DataChangeScope.SUBTREE);
-        } catch (Exception e) {
-            logger.error("InterVpnLinkListener: DataChange listener registration fail!", e);
-            throw new IllegalStateException("InterVpnLinkListener: registration Listener failed.", e);
-        }
+    public void start() {
+        LOG.info("{} start", getClass().getSimpleName());
+        listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
     }
 
     private InstanceIdentifier<InterVpnLink> getWildCardPath() {
         return InstanceIdentifier.create(InterVpnLinks.class).child(InterVpnLink.class);
     }
 
+    @Override
+    public void close() throws Exception {
+        if (listenerRegistration != null) {
+            listenerRegistration.close();
+            listenerRegistration = null;
+        }
+        LOG.info("{} close", getClass().getSimpleName());
+    }
+
     private String getInterVpnLinkIfaceName(String vpnUuid, BigInteger dpnId ) {
         return String.format("InterVpnLink.%s.%s", vpnUuid, dpnId.toString());
     }
@@ -124,42 +111,56 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
     @Override
     protected void add(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink add) {
 
+        LOG.debug("Reacting to IVpnLink {} creation. Vpn1=[name={}  EndpointIp={}]  Vpn2=[name={} endpointIP={}]",
+                add.getName(), add.getFirstEndpoint().getVpnUuid(), add.getFirstEndpoint().getIpAddress(),
+                add.getSecondEndpoint().getVpnUuid(), add.getSecondEndpoint().getIpAddress());
+
         int numberOfDpns = Integer.getInteger(NBR_OF_DPNS_PROPERTY_NAME, 1);
         // Create VpnLink state
-        InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = VpnUtil.getInterVpnLinkStateIid(add.getName());
+        InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid = InterVpnLinkUtil.getInterVpnLinkStateIid(add.getName());
         InterVpnLinkState vpnLinkState = new InterVpnLinkStateBuilder().setInterVpnLinkName(add.getName()).build();
-        MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid, vpnLinkState);
+        MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid, vpnLinkState);
 
         InterVpnLinkKey key = add.getKey();
         Uuid firstEndpointVpnUuid = add.getFirstEndpoint().getVpnUuid();
         Uuid secondEndpointVpnUuid = add.getSecondEndpoint().getVpnUuid();
         // First VPN
+        if ( VpnUtil.getVpnInstance(this.dataBroker, firstEndpointVpnUuid.getValue()) == null ) {
+            String errMsg = "InterVpnLink " + add.getName() + " creation error: could not find 1st endpoint Vpn "
+                    + firstEndpointVpnUuid.getValue();
+            setInError(vpnLinkStateIid, vpnLinkState, errMsg);
+            return;
+        }
         if (!checkVpnAvailability(key, firstEndpointVpnUuid)) {
-            String errMsg = String.format("Vpn already associated with a previous inter-vpn-link {}",
-                                          firstEndpointVpnUuid);
-            logger.error(errMsg);
+            String errMsg = "InterVpnLink " + add.getName() + " creation error: Vpn " + firstEndpointVpnUuid.getValue()
+                    + " is already associated to an inter-vpn-link ";
             setInError(vpnLinkStateIid, vpnLinkState, errMsg);
             return;
         }
 
         // Second VPN
+        if ( VpnUtil.getVpnInstance(this.dataBroker, secondEndpointVpnUuid.getValue()) == null ) {
+            String errMsg = "InterVpnLink " + add.getName() + " creation error: could not find 2nd endpoint Vpn "
+                    + secondEndpointVpnUuid.getValue();
+            setInError(vpnLinkStateIid, vpnLinkState, errMsg);
+            return;
+        }
         if (!checkVpnAvailability(key, secondEndpointVpnUuid)) {
-            String errMsg = String.format("Vpn already associated with a previous inter-vpn-link {}",
-                                          secondEndpointVpnUuid);
-            logger.error(errMsg);
+            String errMsg = "InterVpnLink " + add.getName() + " creation error: Vpn " + secondEndpointVpnUuid.getValue()
+                    + " is already associated with an inter-vpn-link";
             setInError(vpnLinkStateIid, vpnLinkState, errMsg);
             return;
         }
 
         // TODO: Doing like this we are retrieving operative DPNs from MDSAL when we just need one. Fix it
-        List<BigInteger> firstDpnList = VpnUtil.pickRandomDPNs(broker, numberOfDpns, null);
+        List<BigInteger> firstDpnList = VpnUtil.pickRandomDPNs(dataBroker, numberOfDpns, null);
         if (firstDpnList != null && !firstDpnList.isEmpty()) {
             // TODO: Limitation to be solved later
-            // List<BigInteger> secondDpnList = VpnUtil.pickRandomDPNs(broker, numberOfDpns, firstDpnList);
+            // List<BigInteger> secondDpnList = VpnUtil.pickRandomDPNs(dataBroker, numberOfDpns, firstDpnList);
             List<BigInteger> secondDpnList = firstDpnList;
 
-            Integer firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + firstEndpointVpnUuid.getValue());
-            Integer secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + secondEndpointVpnUuid.getValue());
+            Long firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + firstEndpointVpnUuid.getValue());
+            Long secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + secondEndpointVpnUuid.getValue());
             FirstEndpointState firstEndPointState =
                 new FirstEndpointStateBuilder().setVpnUuid(firstEndpointVpnUuid).setDpId(firstDpnList)
                                                .setLportTag(firstVpnLportTag).build();
@@ -167,37 +168,37 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
                 new SecondEndpointStateBuilder().setVpnUuid(secondEndpointVpnUuid).setDpId(secondDpnList)
                                                 .setLportTag(secondVpnLportTag).build();
 
-            InterVpnLinkUtil.updateInterVpnLinkState(broker, add.getName(), InterVpnLinkState.State.Active, firstEndPointState,
-                                            secondEndPointState);
+            InterVpnLinkUtil.updateInterVpnLinkState(dataBroker, add.getName(), InterVpnLinkState.State.Active,
+                                                     firstEndPointState, secondEndPointState);
 
             // Note that in the DPN of the firstEndpoint we install the lportTag of the secondEndpoint and viceversa
-            InterVpnLinkUtil.installLPortDispatcherTableFlow(broker, mdsalManager, add, firstDpnList,
-                                                    secondEndpointVpnUuid, secondVpnLportTag);
-            InterVpnLinkUtil.installLPortDispatcherTableFlow(broker, mdsalManager, add, secondDpnList,
-                                                    firstEndpointVpnUuid, firstVpnLportTag);
+            InterVpnLinkUtil.installLPortDispatcherTableFlow(dataBroker, mdsalManager, add, firstDpnList,
+                                                             secondEndpointVpnUuid, secondVpnLportTag);
+            InterVpnLinkUtil.installLPortDispatcherTableFlow(dataBroker, mdsalManager, add, secondDpnList,
+                                                             firstEndpointVpnUuid, firstVpnLportTag);
             // Update the VPN -> DPNs Map.
             // Note: when a set of DPNs is calculated for Vpn1, these DPNs are added to the VpnToDpn map of Vpn2. Why?
             // because we do the handover from Vpn1 to Vpn2 in those DPNs, so in those DPNs we must know how to reach
             // to Vpn2 targets. If new Vpn2 targets are added later, the Fib will be maintained in these DPNs even if
             // Vpn2 is not physically present there.
-            InterVpnLinkUtil.updateVpnToDpnMap(broker, firstDpnList, secondEndpointVpnUuid);
-            InterVpnLinkUtil.updateVpnToDpnMap(broker, secondDpnList, firstEndpointVpnUuid);
+            InterVpnLinkUtil.updateVpnToDpnMap(dataBroker, firstDpnList, secondEndpointVpnUuid);
+            InterVpnLinkUtil.updateVpnToDpnMap(dataBroker, secondDpnList, firstEndpointVpnUuid);
 
             // Now, if the corresponding flags are activated, there will be some routes exchange
             leakRoutesIfNeeded(add);
         } else {
             // If there is no connection to DPNs, the InterVpnLink is created and the InterVpnLinkState is also created
             // with the corresponding LPortTags but no DPN is assigned since there is no DPN operative.
-            Integer firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + firstEndpointVpnUuid.getValue());
-            Integer secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + secondEndpointVpnUuid.getValue());
+            Long firstVpnLportTag = allocateVpnLinkLportTag(key.getName() + firstEndpointVpnUuid.getValue());
+            Long secondVpnLportTag = allocateVpnLinkLportTag(key.getName() + secondEndpointVpnUuid.getValue());
             FirstEndpointState firstEndPointState =
                 new FirstEndpointStateBuilder().setVpnUuid(firstEndpointVpnUuid)
                                                .setLportTag(firstVpnLportTag).build();
             SecondEndpointState secondEndPointState =
                 new SecondEndpointStateBuilder().setVpnUuid(secondEndpointVpnUuid)
                                                 .setLportTag(secondVpnLportTag).build();
-            InterVpnLinkUtil.updateInterVpnLinkState(broker, add.getName(), InterVpnLinkState.State.Error, firstEndPointState,
-                                            secondEndPointState);
+            InterVpnLinkUtil.updateInterVpnLinkState(dataBroker, add.getName(), InterVpnLinkState.State.Error,
+                                                     firstEndPointState, secondEndPointState);
         }
 
 
@@ -230,9 +231,7 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
             leakRoutes(vpnLink, vpn1Uuid, vpn2Uuid, originsToConsider);
 
             // 2nd Endpoint ==> 1st endpoint
-            leakRoutes(vpnLink, vpnLink.getSecondEndpoint().getVpnUuid().getValue(),
-                       vpnLink.getFirstEndpoint().getVpnUuid().getValue(),
-                       originsToConsider);
+            leakRoutes(vpnLink, vpn2Uuid, vpn1Uuid, originsToConsider);
         }
 
         // Static routes in Vpn1 pointing to Vpn2's endpoint
@@ -244,15 +243,15 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
 
     private void leakRoutes(InterVpnLink vpnLink, String srcVpnUuid, String dstVpnUuid,
                             List<RouteOrigin> originsToConsider) {
-        String srcVpnRd = VpnUtil.getVpnRd(broker, srcVpnUuid);
-        String dstVpnRd = VpnUtil.getVpnRd(broker, dstVpnUuid);
-        List<VrfEntry> srcVpnRemoteVrfEntries = VpnUtil.getVrfEntriesByOrigin(broker, srcVpnRd, originsToConsider);
+        String srcVpnRd = VpnUtil.getVpnRd(dataBroker, srcVpnUuid);
+        String dstVpnRd = VpnUtil.getVpnRd(dataBroker, dstVpnUuid);
+        List<VrfEntry> srcVpnRemoteVrfEntries = VpnUtil.getVrfEntriesByOrigin(dataBroker, srcVpnRd, originsToConsider);
         for ( VrfEntry vrfEntry : srcVpnRemoteVrfEntries ) {
             long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
                                              VpnUtil.getNextHopLabelKey(dstVpnRd, vrfEntry.getDestPrefix()));
 
-            VpnUtil.leakRoute(broker, bgpManager, vpnLink, srcVpnUuid, dstVpnUuid,
-                              vrfEntry.getDestPrefix(), label);
+            InterVpnLinkUtil.leakRoute(dataBroker, bgpManager, vpnLink, srcVpnUuid, dstVpnUuid, vrfEntry.getDestPrefix(),
+                                       label);
         }
     }
 
@@ -265,9 +264,9 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
      */
     private void leakExtraRoutesToVpnEndpoint(InterVpnLink vpnLink, String vpn1Uuid, String vpn2Uuid) {
 
-        String vpn1Rd = VpnUtil.getVpnRd(broker, vpn1Uuid);
+        String vpn1Rd = VpnUtil.getVpnRd(dataBroker, vpn1Uuid);
         String vpn2Endpoint = vpnLink.getSecondEndpoint().getIpAddress().getValue();
-        List<VrfEntry> allVpnVrfEntries = VpnUtil.getAllVrfEntries(broker, vpn1Rd);
+        List<VrfEntry> allVpnVrfEntries = VpnUtil.getAllVrfEntries(dataBroker, vpn1Rd);
         for ( VrfEntry vrfEntry : allVpnVrfEntries ) {
             if ( vrfEntry.getNextHopAddressList() != null
                 && vrfEntry.getNextHopAddressList().contains(vpn2Endpoint) ) {
@@ -276,7 +275,7 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
                 long label = VpnUtil.getUniqueId(idManager, VpnConstants.VPN_IDPOOL_NAME,
                                                   VpnUtil.getNextHopLabelKey(vpn1Rd, vrfEntry.getDestPrefix()));
 
-                VpnUtil.leakRoute(broker, bgpManager, vpnLink, vpn2Uuid, vpn1Uuid, vrfEntry.getDestPrefix(),
+                InterVpnLinkUtil.leakRoute(dataBroker, bgpManager, vpnLink, vpn2Uuid, vpn1Uuid, vrfEntry.getDestPrefix(),
                                   label, RouteOrigin.value(vrfEntry.getOrigin()));
             }
         }
@@ -286,7 +285,7 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
     private boolean checkVpnAvailability(InterVpnLinkKey key, Uuid vpnId) {
         Preconditions.checkNotNull(vpnId);
 
-        List<InterVpnLink> interVpnLinks = VpnUtil.getAllInterVpnLinks(broker);
+        List<InterVpnLink> interVpnLinks = InterVpnLinkUtil.getAllInterVpnLinks(dataBroker);
         if ( interVpnLinks != null ) {
             for (InterVpnLink interVpnLink : interVpnLinks) {
                 if (!key.equals(interVpnLink.getKey())
@@ -303,53 +302,41 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
     @Override
     protected void remove(InstanceIdentifier<InterVpnLink> identifier, InterVpnLink del) {
 
+        LOG.debug("Reacting to InterVpnLink {} removal", del.getName());
         // Remove learnt routes
         // Remove entries in the LPortDispatcher table
         // Remove the corresponding entries in InterVpnLinkState
 
         // For each endpoint, remove all routes that have been learnt by intervpnLink
         String vpn1Uuid = del.getFirstEndpoint().getVpnUuid().getValue();
-        String rd1 = VpnUtil.getVpnRdFromVpnInstanceConfig(broker, vpn1Uuid);
-        VpnUtil.removeVrfEntriesByOrigin(broker, rd1, RouteOrigin.INTERVPN);
-        VpnUtil.removeVrfEntriesByNexthop(broker, rd1, del.getSecondEndpoint().getIpAddress().getValue());
+        String rd1 = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpn1Uuid);
+        LOG.debug("Removing leaked routes in VPN {}  rd={}", vpn1Uuid, rd1);
+        VpnUtil.removeVrfEntriesByOrigin(dataBroker, rd1, RouteOrigin.INTERVPN);
+        VpnUtil.removeVrfEntriesByNexthop(dataBroker, rd1, del.getSecondEndpoint().getIpAddress().getValue());
 
         String vpn2Uuid = del.getSecondEndpoint().getVpnUuid().getValue();
-        String rd2 = VpnUtil.getVpnRdFromVpnInstanceConfig(broker, vpn2Uuid);
-        VpnUtil.removeVrfEntriesByOrigin(broker, rd2, RouteOrigin.INTERVPN);
-        VpnUtil.removeVrfEntriesByNexthop(broker, rd2, del.getFirstEndpoint().getIpAddress().getValue());
-
-        InterVpnLinkState interVpnLinkState = VpnUtil.getInterVpnLinkState(broker, del.getName());
-        Integer firstEndpointLportTag = interVpnLinkState.getFirstEndpointState().getLportTag();
-
-        Integer secondEndpointLportTag = interVpnLinkState.getSecondEndpointState().getLportTag();
-
-        // Remmoving the flow entries in LPortDispatcher table in 1st Endpoint DPNs
-        for ( BigInteger dpnId : interVpnLinkState.getFirstEndpointState().getDpId() ) {
-            String flowRef = InterVpnLinkUtil.getLportDispatcherFlowRef(del.getName(), secondEndpointLportTag);
-            FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-            Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
-                                         .setTableId(NwConstants.LPORT_DISPATCHER_TABLE).setFlowName(flowRef)
-                                         .build();
-            mdsalManager.removeFlow(dpnId, flow);
-
-            // Also remove the 'fake' iface from the VpnToDpn map
-            VpnUtil.removeIfaceFromVpnToDpnMap(broker, rd1, dpnId, getInterVpnLinkIfaceName(vpn1Uuid, dpnId));
+        String rd2 = VpnUtil.getVpnRdFromVpnInstanceConfig(dataBroker, vpn2Uuid);
+        LOG.debug("Removing leaked routes in VPN {}  rd={}", vpn2Uuid, rd2);
+        VpnUtil.removeVrfEntriesByOrigin(dataBroker, rd2, RouteOrigin.INTERVPN);
+        VpnUtil.removeVrfEntriesByNexthop(dataBroker, rd2, del.getFirstEndpoint().getIpAddress().getValue());
+
+        Optional<InterVpnLinkState> optIVpnLinkState = InterVpnLinkUtil.getInterVpnLinkState(dataBroker, del.getName());
+        if ( optIVpnLinkState.isPresent() ) {
+            InterVpnLinkState interVpnLinkState = optIVpnLinkState.get();
+            Long firstEndpointLportTag = interVpnLinkState.getFirstEndpointState().getLportTag();
+            Long secondEndpointLportTag = interVpnLinkState.getSecondEndpointState().getLportTag();
+            removeVpnLinkEndpointFlows(del.getName(), rd1, vpn1Uuid,
+                    interVpnLinkState.getFirstEndpointState().getDpId(),
+                    secondEndpointLportTag.intValue(),
+                    del.getSecondEndpoint().getIpAddress().getValue());
+            removeVpnLinkEndpointFlows(del.getName(), rd2, vpn2Uuid,
+                    interVpnLinkState.getSecondEndpointState().getDpId(),
+                    firstEndpointLportTag.intValue(),
+                    del.getFirstEndpoint().getIpAddress().getValue());
         }
 
-        // Removing the flow entries in 2nd Endpoint DPNs
-        for ( BigInteger dpnId : interVpnLinkState.getSecondEndpointState().getDpId() ) {
-            String flowRef = InterVpnLinkUtil.getLportDispatcherFlowRef(del.getName(), firstEndpointLportTag);
-            FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-            Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
-                                         .setTableId(NwConstants.LPORT_DISPATCHER_TABLE).setFlowName(flowRef)
-                                         .build();
-            mdsalManager.removeFlow(dpnId, flow);
-
-            // Also remove the 'fake' iface from the VpnToDpn map
-            VpnUtil.removeIfaceFromVpnToDpnMap(broker, rd2, dpnId, getInterVpnLinkIfaceName(vpn2Uuid, dpnId));
-        }
-
-        // Release idManager wit LPortTag associated to endpoints
+        // Release idManager with LPortTag associated to endpoints
+        LOG.debug("Releasing InterVpnLink {} endpoints LportTags", del.getName());
         InterVpnLinkKey key = del.getKey();
         Uuid firstEndpointVpnUuid = del.getFirstEndpoint().getVpnUuid();
         Uuid secondEndpointVpnUuid = del.getSecondEndpoint().getVpnUuid();
@@ -361,24 +348,53 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
         // At this point. we need to check if is there any entry in FIB table pointing to LPortDispatcher table.
         // Remove it in that case.
 
-        // 1stEndPoint dpns
-        for ( BigInteger dpnId : interVpnLinkState.getFirstEndpointState().getDpId() ) {
-            removeRouteFromInterVpnLink(dpnId, del.getName(), del.getSecondEndpoint().getIpAddress().getValue());
-        }
+        // Removing the InterVpnLinkState
+        InstanceIdentifier<InterVpnLinkState> interVpnLinkStateIid = InterVpnLinkUtil.getInterVpnLinkStateIid(del.getName());
+        VpnUtil.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
+    }
 
-        // 2ndtEndPoint dpns
-        for ( BigInteger dpnId : interVpnLinkState.getSecondEndpointState().getDpId() ) {
-            removeRouteFromInterVpnLink(dpnId, del.getName(), del.getFirstEndpoint().getIpAddress().getValue());
+    private void removeVpnLinkEndpointFlows( String interVpnLinkName, String rd, String vpnUuid, List<BigInteger> dpns,
+                                             int otherEndpointLportTag, String otherEndpointIpAddr ) {
+        LOG.debug("Removing endpoint flows for vpn {}.  InterVpnLink={}.  OtherEndpointLportTag={}",
+                vpnUuid, interVpnLinkName, otherEndpointLportTag);
+        if ( dpns == null ) {
+            LOG.debug("VPN {} endpoint is not instantiated in any DPN for InterVpnLink {}",
+                    vpnUuid, interVpnLinkName);
+            return;
         }
 
-        // Removing the InterVpnLinkState
-        InstanceIdentifier<InterVpnLinkState> interVpnLinkStateIid = VpnUtil.getInterVpnLinkStateIid(del.getName());
-        VpnUtil.delete(broker, LogicalDatastoreType.CONFIGURATION, interVpnLinkStateIid);
+        for ( BigInteger dpnId : dpns ) {
+            try {
+                // Removing flow from LportDispatcher table
+                String flowRef = InterVpnLinkUtil.getLportDispatcherFlowRef(interVpnLinkName, otherEndpointLportTag);
+                FlowKey flowKey = new FlowKey(new FlowId(flowRef));
+                Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
+                        .setTableId(NwConstants.LPORT_DISPATCHER_TABLE).setFlowName(flowRef)
+                        .build();
+                mdsalManager.removeFlow(dpnId, flow);
+
+                // Removing flow from Fib table
+                String fibFlowRef = getInterVpnFibFlowRef(dpnId, NwConstants.L3_FIB_TABLE, interVpnLinkName,
+                        otherEndpointIpAddr);
+                FlowKey fibFlowKey = new FlowKey(new FlowId(fibFlowRef));
+                Flow fibFlow = new FlowBuilder().setKey(fibFlowKey).setId(new FlowId(fibFlowRef))
+                        .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(fibFlowRef).build();
+                mdsalManager.removeFlow(dpnId, fibFlow);
+
+                // Also remove the 'fake' iface from the VpnToDpn map
+                VpnUtil.removeIfaceFromVpnToDpnMap(dataBroker, rd, dpnId, getInterVpnLinkIfaceName(vpnUuid, dpnId));
+
+            } catch ( Exception e ) {
+                // Whatever happens it should not stop it from trying to remove as much as possible
+                LOG.warn("Error while removing InterVpnLink {} Endpoint flows on dpn {}. Reason: {}",
+                        interVpnLinkName, dpnId, e);
+            }
+        }
     }
 
     private void releaseVpnLinkLPortTag(String idKey) {
-        ReleaseIdInput releaseIdInput = new ReleaseIdInputBuilder().setPoolName(IfmConstants.IFM_IDPOOL_NAME)
-                                                                   .setIdKey(idKey).build();
+        ReleaseIdInput releaseIdInput =
+                new ReleaseIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME).setIdKey(idKey).build();
         idManager.releaseId(releaseIdInput);
     }
 
@@ -387,36 +403,29 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
      // TODO
     }
 
-    private String getInterVpnFibFlowRef(BigInteger dpnId, short tableId, String interVpnLinkName, String nextHop ) {
-        return new StringBuilder(64).append(VpnConstants.FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
-            .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-            .append(interVpnLinkName).append(NwConstants.FLOWID_SEPARATOR)
-            .append(nextHop).toString();
+    private String getInterVpnFibFlowRef(BigInteger dpnId, short tableId, String interVpnLinkName,  String nextHop ) {
+        return new StringBuilder(64).append(VpnConstants.FLOWID_PREFIX).append(dpnId)
+                .append(NwConstants.FLOWID_SEPARATOR).append(tableId)
+                .append(NwConstants.FLOWID_SEPARATOR).append(interVpnLinkName)
+                .append(NwConstants.FLOWID_SEPARATOR).append(nextHop)
+                .toString();
     }
 
-    private void removeRouteFromInterVpnLink(BigInteger dpnId, String interVpnLinkName, final String nextHop) {
-        String flowRef = getInterVpnFibFlowRef(dpnId, NwConstants.L3_FIB_TABLE, interVpnLinkName, nextHop);
-        FlowKey flowKey = new FlowKey(new FlowId(flowRef));
-        Flow flow = new FlowBuilder().setKey(flowKey).setId(new FlowId(flowRef))
-                .setTableId(NwConstants.L3_FIB_TABLE).setFlowName(flowRef)
-                .build();
-        mdsalManager.removeFlow(dpnId, flow);
-    }
-
-
-    private Integer allocateVpnLinkLportTag(String idKey) {
+    private Long allocateVpnLinkLportTag(String idKey) {
         AllocateIdInput getIdInput =
-                new AllocateIdInputBuilder().setPoolName(IfmConstants.IFM_IDPOOL_NAME).setIdKey(idKey).build();
+                new AllocateIdInputBuilder().setPoolName(VpnConstants.PSEUDO_LPORT_TAG_ID_POOL_NAME)
+                        .setIdKey(idKey)
+                        .build();
         try {
             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
             RpcResult<AllocateIdOutput> rpcResult = result.get();
-            if(rpcResult.isSuccessful()) {
-                return rpcResult.getResult().getIdValue().intValue();
+            if (rpcResult.isSuccessful()) {
+                return rpcResult.getResult().getIdValue();
             } else {
-                logger.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
+                LOG.warn("RPC Call to Get Unique Id returned with Errors {}", rpcResult.getErrors());
             }
         } catch (InterruptedException | ExecutionException e) {
-            logger.warn("Exception when getting Unique Id",e);
+            LOG.warn("Exception when getting Unique Id",e);
         }
         return INVALID_ID;
     }
@@ -424,12 +433,13 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
     protected void setInError(final InstanceIdentifier<InterVpnLinkState> vpnLinkStateIid,
                               final InterVpnLinkState vpnLinkState,
                               String errorMsg) {
+        LOG.error("Setting InterVpnLink {} in error. Reason: {}", vpnLinkState.getInterVpnLinkName(), errorMsg);
         // Setting InterVPNLink in error state in MDSAL
         InterVpnLinkState vpnLinkErrorState =
-           new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
-                                                     .setErrorDescription(errorMsg)
-                                                     .build();
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
+            new InterVpnLinkStateBuilder(vpnLinkState).setState(InterVpnLinkState.State.Error)
+                                                      .setErrorDescription(errorMsg)
+                                                      .build();
+        WriteTransaction tx = dataBroker.newWriteOnlyTransaction();
         tx.put(LogicalDatastoreType.CONFIGURATION, vpnLinkStateIid, vpnLinkErrorState, true);
         tx.submit();
 
@@ -442,13 +452,13 @@ public class InterVpnLinkListener extends AbstractDataChangeListener<InterVpnLin
         Futures.addCallback(eventFuture, new FutureCallback<Object>() {
             @Override
             public void onFailure(Throwable error) {
-                logger.warn("Error when sending notification about InterVpnLink creation issue. InterVpnLink name={}. Error={}",
+                LOG.warn("Error when sending notification about InterVpnLink creation issue. InterVpnLink name={}. Error={}",
                             vpnLinkState.getInterVpnLinkName(), vpnLinkState, error);
             }
 
             @Override
             public void onSuccess(Object arg) {
-                logger.trace("Error notification for InterVpnLink successfully sent. VpnLink={} error={}",
+                LOG.trace("Error notification for InterVpnLink successfully sent. VpnLink={} error={}",
                              vpnLinkState.getInterVpnLinkName(), vpnLinkState);
             }
         });