NETVIRT-1235 : Prefix-To-Interface ds not cleared . 34/71634/11
authoreaksahu <a.k.sahu@ericsson.com>
Mon, 30 Apr 2018 07:47:57 +0000 (13:17 +0530)
committerSam Hague <shague@redhat.com>
Wed, 13 Jun 2018 19:02:01 +0000 (19:02 +0000)
We have 2 primary adj  stored in VpnInterfaceOp DS. When VM is deleted , 2 FIB entries are removed.
In cleanupOpDataForFib() , when we remove first primary adj from VpnInterfaceOp DS , it triggers update in VpnInterfaceOp listener.
We ignore update of VpnInterfaceOp. When 2^nd^ / final primary adj is removed , we delete the VpnInterfaceOp entry.
This leads to removal of prefix-to-interface for 2nd primary adj. First primary adj , always remains stale.

Change-Id: I8fddd9a5d1a7425533ca1c45f81385f60bfa0d4f
Signed-off-by: eaksahu <a.k.sahu@ericsson.com>
fibmanager/impl/src/main/java/org/opendaylight/netvirt/fibmanager/VrfEntryListener.java
vpnmanager/api/src/main/yang/odl-l3vpn.yang
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceOpListener.java

index 3f5778cb19084b964b884b34a9941f172e9aee4f..7a1020de6c8291bcb75cfd97de0eddb2eea41c1b 100755 (executable)
@@ -30,8 +30,10 @@ import javax.annotation.PostConstruct;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
@@ -91,6 +93,8 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev15033
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.AdjacencyBuilder;
 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.prefix.to._interface.vpn.ids.PrefixesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
@@ -1272,7 +1276,7 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
         public List<ListenableFuture<Void>> call() {
             // If another renderer(for eg : CSS) needs to be supported, check can be performed here
             // to call the respective helpers.
-            return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
+            return Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(tx -> {
                 //First Cleanup LabelRouteInfo
                 //TODO(KIRAN) : Move the below block when addressing iRT/eRT for L3VPN Over VxLan
                 LOG.debug("cleanupVpnInterfaceWorker: rd {} prefix {}", rd, prefixInfo.getIpAddress());
@@ -1344,31 +1348,59 @@ public class VrfEntryListener extends AsyncDataTreeChangeListenerBase<VrfEntry,
                                 VpnExtraRouteHelper.getUsedRdsIdentifier(vpnId, vrfEntry.getDestPrefix()));
                     }
                 }
-                Optional<AdjacenciesOp> optAdjacencies =
-                    MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
-                                   FibUtil.getAdjListPathOp(ifName, vpnName));
-                int numAdj = 0;
-                if (optAdjacencies.isPresent()) {
-                    numAdj = optAdjacencies.get().getAdjacency().size();
-                }
-                //remove adjacency corr to prefix
-                if (numAdj > 1) {
-                    LOG.info("cleanUpOpDataForFib: remove adjacency for prefix: {} {} vpnName {}", vpnId,
-                             vrfEntry.getDestPrefix(), vpnName);
-                    tx.delete(LogicalDatastoreType.OPERATIONAL,
-                              FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()));
-                } else {
-                    //this is last adjacency (or) no more adjacency left for this vpn interface, so
-                    //clean up the vpn interface from DpnToVpn list
-                    LOG.info("Clean up vpn interface {} from dpn {} to vpn {} list.",
-                             ifName, prefixInfo.getDpnId(), rd);
-                    tx.delete(LogicalDatastoreType.OPERATIONAL,
-                              FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
-                }
+                handleAdjacencyAndVpnOpInterfaceDeletion(vrfEntry, ifName, vpnName, tx);
             }));
         }
     }
 
+    /**
+     * Check all the adjacency in VpnInterfaceOpData and decide whether to delete the entire interface or only adj.
+     * Remove Adjacency from VPNInterfaceOpData.
+     * if Adjacency != primary.
+     * if Adjacency == primary , then mark it for deletion.
+     * Remove entire VPNinterfaceOpData Entry.
+     * if sie of Adjacency <= 2 and all are marked for deletion , delete the entire VPNinterface Op entry.
+     * @param vrfEntry - VrfEntry removed
+     * @param ifName - Interface name from VRFentry
+     * @param vpnName - VPN name of corresponding VRF
+     * @param tx - ReadWrite Tx
+     * @throws ReadFailedException - Exception thrown in case of read failed
+     */
+    private void handleAdjacencyAndVpnOpInterfaceDeletion(VrfEntry vrfEntry, String ifName, String vpnName,
+                                                          ReadWriteTransaction tx) throws ReadFailedException {
+        InstanceIdentifier<Adjacency> adjacencyIid =
+                FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix());
+        Optional<Adjacency> adjacencyOptional = tx.read(LogicalDatastoreType.OPERATIONAL, adjacencyIid).checkedGet();
+        if (adjacencyOptional.isPresent()) {
+            if (adjacencyOptional.get().getAdjacencyType() != Adjacency.AdjacencyType.PrimaryAdjacency) {
+                tx.delete(LogicalDatastoreType.OPERATIONAL,
+                        FibUtil.getAdjacencyIdentifierOp(ifName, vpnName, vrfEntry.getDestPrefix()));
+            } else {
+                tx.merge(LogicalDatastoreType.OPERATIONAL, adjacencyIid,
+                        new AdjacencyBuilder(adjacencyOptional.get()).setMarkedForDeletion(true).build());
+            }
+        }
+
+        Optional<AdjacenciesOp> optAdjacencies =
+                tx.read(LogicalDatastoreType.OPERATIONAL,
+                        FibUtil.getAdjListPathOp(ifName, vpnName)).checkedGet();
+
+        if (!optAdjacencies.isPresent() || optAdjacencies.get().getAdjacency() == null) {
+            return;
+        }
+
+        if (optAdjacencies.get().getAdjacency().stream().count() <= 2
+                && optAdjacencies.get().getAdjacency().stream().allMatch(adjacency ->
+                adjacency.getAdjacencyType() == Adjacency.AdjacencyType.PrimaryAdjacency
+                        && adjacency.isMarkedForDeletion() != null
+                        && adjacency.isMarkedForDeletion()
+        )) {
+            LOG.info("Clean up vpn interface {} to vpn {} list.", ifName, vpnName);
+            tx.delete(LogicalDatastoreType.OPERATIONAL,
+                    FibUtil.getVpnInterfaceOpDataEntryIdentifier(ifName, vpnName));
+        }
+    }
+
     private void deleteFibEntries(final InstanceIdentifier<VrfEntry> identifier, final VrfEntry vrfEntry) {
         final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
         final String rd = vrfTableKey.getRouteDistinguisher();
index d17844b819e6bae764281b2613b189f7d3a2a900..a9c2b9ebbf86bbf7c3616be5a3f7550540f89986 100644 (file)
@@ -41,17 +41,26 @@ module odl-l3vpn {
                 }
                 default "extra-route";
             }
-            leaf label { type uint32; config "false"; } /* optional */
             leaf mac_address {type string;} /* optional */
             leaf subnet_id {type yang:uuid;} /* optional */
             leaf subnet_gateway_ip {type string;}  /* optional */
-            leaf subnet_gateway_mac_address {type string; config "false";} /* optional */
-            leaf vrf-id { type string; config "false"; }
             leaf phys-network-func {
                 type boolean;
                 default false;
                 description "Value of True indicates this is an adjacency of a device in a provider network";
             }
+            uses adjacency-op-data;
+        }
+    }
+
+    grouping adjacency-op-data{
+        leaf label { type uint32; config "false"; } /* optional */
+        leaf subnet_gateway_mac_address {type string; config "false";} /* optional */
+        leaf vrf-id { type string; config "false"; }
+        leaf marked_for_deletion {
+            config "false";
+            type boolean;
+            description "This flag if true suggest this adjancency has been marked for deletion";
         }
     }
 
index db1803f503aed5d139f4b9b38ef4dd598bebf3c8..828846e57cbc4bbf290fbffc94423c0306b83457 100644 (file)
@@ -126,7 +126,8 @@ public class VpnInterfaceOpListener extends AsyncDataTreeChangeListenerBase<VpnI
             if (vpnInstOp != null && adjList != null && adjList.size() > 0) {
                 /*
                  * When a VPN Interface is removed by FibManager (aka VrfEntryListener and its cohorts),
-                 * one adjacency for that VPN Interface will be hanging around along with that
+                 * one adjacency or two adjacency (in case of dual-stack)
+                 * for that VPN Interface will be hanging around along with that
                  * VPN Interface.   That adjacency could be primary (or) non-primary.
                  * If its a primary adjacency, then a prefix-to-interface entry will be available for the
                  * same.  If its a non-primary adjacency, then a prefix-to-interface entry will not be
@@ -205,7 +206,7 @@ public class VpnInterfaceOpListener extends AsyncDataTreeChangeListenerBase<VpnI
     @Override
     protected void update(final InstanceIdentifier<VpnInterfaceOpDataEntry> identifier,
             final VpnInterfaceOpDataEntry original, final VpnInterfaceOpDataEntry update) {
-        LOG.info("update: interface {} vpn {}. Ignoring", original.getName(), original.getVpnInstanceName());
+        LOG.info("update: interface {} vpn {}", original.getName(), original.getVpnInstanceName());
     }
 
     @Override