ARP Responder stale flow after undeployment 24/83024/10
authorSurendar Raju <surendar.raju@ericsson.com>
Fri, 12 Jul 2019 07:12:32 +0000 (12:42 +0530)
committerKarthikeyan Krishnan <karthikeyangceb007@gmail.com>
Wed, 12 Feb 2020 08:49:23 +0000 (08:49 +0000)
Issue:
======

At scale, its possible that after all ports are deleted , even if subnet
is deleted later , during VpnInterface remove processing , backpull of
Neutron DS like subnets is bound to fail. Due to this , ArpResponder flow
deletion might fail.

Fix:
===
Subnet-Gateway-IP which is read from Neutron Subnet DS, will be stored in
VpnInterface oper DS, thus avoiding backpull.

Change-Id: I703091e6cde2f7b8b31488178d72eee703aa712d
Signed-off-by: Surendar Raju <surendar.raju@ericsson.com>
vpnmanager/api/src/main/yang/odl-l3vpn.yang
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInstanceListener.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnInterfaceManager.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/VpnUtil.java
vpnmanager/impl/src/main/java/org/opendaylight/netvirt/vpnmanager/arp/responder/ArpResponderHandler.java

index 2d49cffa5702d53c7cbc8c68479e3a370b3c8586..7cfe0151851c6fa3700a48ade06546a9ec77fb2c 100644 (file)
@@ -223,6 +223,9 @@ module odl-l3vpn {
             leaf gateway-mac-address {
                 type string;
             }
+            leaf gateway-ip-address {
+                type string;
+            }
             leaf lport-tag {
                 type uint32;
             }
index 72601a369c41c882555473d75250322f968c781e..38ebd0326f4e2bff74e38490aed3454832435086 100644 (file)
@@ -152,10 +152,17 @@ public class VpnInstanceListener extends AsyncDataTreeChangeListenerBase<VpnInst
         } else {
             jobCoordinator.enqueueJob("VPN-" + vpnName, () ->
                 Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
-                    VpnInstanceOpDataEntryBuilder builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
-                            .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
-                    InstanceIdentifier<VpnInstanceOpDataEntry> id =
-                            VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
+                    VpnInstanceOpDataEntryBuilder builder = null;
+                    InstanceIdentifier<VpnInstanceOpDataEntry> id = null;
+                    if (primaryRd != null) {
+                        builder = new VpnInstanceOpDataEntryBuilder().setVrfId(primaryRd)
+                                .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
+                        id = VpnUtil.getVpnInstanceOpDataIdentifier(primaryRd);
+                    } else {
+                        builder = new VpnInstanceOpDataEntryBuilder().setVrfId(vpnName)
+                                .setVpnState(VpnInstanceOpDataEntry.VpnState.PendingDelete);
+                        id = VpnUtil.getVpnInstanceOpDataIdentifier(vpnName);
+                    }
                     tx.merge(id, builder.build());
 
                     LOG.info("{} call: Operational status set to PENDING_DELETE for vpn {} with rd {}",
index 52eefcc04d65ce5888cc1d8a016bac545470ef8e..ac63cae8f6c3e97cc6a55b72fff6cc40bec661ff 100755 (executable)
@@ -758,12 +758,13 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             adjacencies = vpnInteface.get().augmentation(Adjacencies.class);
             if (adjacencies == null) {
                 addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, null/*adjacencies*/, lportTag,
-                        null/*gwMac*/, writeOperTxn);
+                        null/*gwMac*/,  null/*gatewayIp*/, writeOperTxn);
                 return;
             }
         }
         // Get the rd of the vpn instance
         String nextHopIp = null;
+        String gatewayIp = null;
         try {
             nextHopIp = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId);
         } catch (Exception e) {
@@ -811,7 +812,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                         vpnUtil.getVpnId(vpnName), prefix), prefixes, true);
                 final Uuid subnetId = nextHop.getSubnetId();
 
-                String gatewayIp = nextHop.getSubnetGatewayIp();
+                gatewayIp = nextHop.getSubnetGatewayIp();
                 if (gatewayIp == null) {
                     Optional<String> gatewayIpOptional = vpnUtil.getVpnSubnetGatewayIp(subnetId);
                     if (gatewayIpOptional.isPresent()) {
@@ -906,7 +907,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
 
         AdjacenciesOp aug = VpnUtil.getVpnInterfaceOpDataEntryAugmentation(value);
         addVpnInterfaceToOperational(vpnName, interfaceName, dpnId, aug, lportTag,
-                gwMac.isPresent() ? gwMac.get() : null, writeOperTxn);
+                gwMac.isPresent() ? gwMac.get() : null, gatewayIp, writeOperTxn);
 
         L3vpnInput input = new L3vpnInput().setNextHopIp(nextHopIp).setL3vni(l3vni.longValue()).setPrimaryRd(primaryRd)
                 .setGatewayMac(gwMac.orNull()).setInterfaceName(interfaceName)
@@ -923,10 +924,10 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     private void addVpnInterfaceToOperational(String vpnName, String interfaceName, Uint64 dpnId, AdjacenciesOp aug,
-                                              long lportTag, String gwMac,
+                                              long lportTag, String gwMac, String gwIp,
                                               TypedWriteTransaction<Operational> writeOperTxn) {
         VpnInterfaceOpDataEntry opInterface =
-              VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac);
+              VpnUtil.getVpnInterfaceOpDataEntry(interfaceName, vpnName, aug, dpnId, lportTag, gwMac, gwIp);
         InstanceIdentifier<VpnInterfaceOpDataEntry> interfaceId = VpnUtil
             .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
         writeOperTxn.put(interfaceId, opInterface, CREATE_MISSING_PARENTS);
@@ -1385,16 +1386,22 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
         try {
             InstanceIdentifier<VpnInterfaceOpDataEntry> identifier = VpnUtil
                     .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
-            InstanceIdentifier<AdjacenciesOp> path = identifier.augmentation(AdjacenciesOp.class);
-            Optional<AdjacenciesOp> adjacencies = SingleTransactionDataBroker.syncReadOptional(dataBroker,
-                    LogicalDatastoreType.OPERATIONAL, path);
-            boolean isLearntIP = false;
+            Optional<VpnInterfaceOpDataEntry> vpnInterfaceOpDataEnteryOptional =
+                    SingleTransactionDataBroker.syncReadOptional(dataBroker,
+                            LogicalDatastoreType.OPERATIONAL, identifier);
+            boolean isLearntIP = Boolean.FALSE;
             String primaryRd = vpnUtil.getVpnRd(vpnName);
             LOG.info("removeAdjacenciesFromVpn: For interface {} on dpn {} RD recovered for vpn {} as rd {}",
                     interfaceName, dpnId, vpnName, primaryRd);
-            if (adjacencies.isPresent() && adjacencies.get().getAdjacency() != null
-                    && !adjacencies.get().getAdjacency().isEmpty()) {
-                List<Adjacency> nextHops = adjacencies.get().getAdjacency();
+            if (!vpnInterfaceOpDataEnteryOptional.isPresent()) {
+                LOG.error("removeAdjacenciesFromVpn: VpnInterfaceOpDataEntry-Oper DS is absent for Interface {} "
+                        + "on vpn {} dpn {}", interfaceName, vpnName, dpnId);
+                return;
+            }
+            AdjacenciesOp adjacencies = vpnInterfaceOpDataEnteryOptional.get().augmentation(AdjacenciesOp.class);
+
+            if (adjacencies != null && !adjacencies.getAdjacency().isEmpty()) {
+                List<Adjacency> nextHops = adjacencies.getAdjacency();
                 LOG.info("removeAdjacenciesFromVpn: NextHops for interface {} on dpn {} for vpn {} are {}",
                         interfaceName, dpnId, vpnName, nextHops);
                 for (Adjacency nextHop : nextHops) {
@@ -1414,6 +1421,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                             nhList = nextHop.getNextHopIpList() != null ? nextHop.getNextHopIpList()
                                     : emptyList();
                             removeGwMacAndArpResponderFlows(nextHop, vpnId, dpnId, lportTag, gwMac,
+                                    vpnInterfaceOpDataEnteryOptional.get().getGatewayIpAddress(),
                                     interfaceName, writeInvTxn);
                         }
                         if (!nhList.isEmpty()) {
@@ -1531,7 +1539,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
     }
 
     private void removeGwMacAndArpResponderFlows(Adjacency nextHop, Uint32 vpnId, Uint64 dpnId,
-                                                 int lportTag, String gwMac, String interfaceName,
+                                                 int lportTag, String gwMac, String gwIp, String interfaceName,
                                                  TypedReadWriteTransaction<Configuration> writeInvTxn)
             throws ExecutionException, InterruptedException {
         final Uuid subnetId = nextHop.getSubnetId();
@@ -1541,7 +1549,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
             // to remove the flows for the same here from the L3_GW_MAC_TABLE.
             vpnUtil.setupGwMacIfExternalVpn(dpnId, interfaceName, vpnId, writeInvTxn, NwConstants.DEL_FLOW, gwMac);
         }
-        arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, nextHop.getSubnetGatewayIp(),
+        arpResponderHandler.removeArpResponderFlow(dpnId, lportTag, interfaceName, gwIp,
                 subnetId);
     }
 
@@ -2050,8 +2058,7 @@ public class VpnInterfaceManager extends AsyncDataTreeChangeListenerBase<VpnInte
                 VpnInterfaceOpDataEntry newVpnIntf =
                         VpnUtil.getVpnInterfaceOpDataEntry(currVpnIntf.getName(), currVpnIntf.getVpnInstanceName(),
                                 aug, dpnId, currVpnIntf.getLportTag().toJava(),
-                                currVpnIntf.getGatewayMacAddress());
-
+                                currVpnIntf.getGatewayMacAddress(), currVpnIntf.getGatewayIpAddress());
                 writeOperTxn.merge(identifier, newVpnIntf, CREATE_MISSING_PARENTS);
             }
         } catch (ReadFailedException e) {
index e0979ae7cd5b50e328cab29206a70f4bbe73326d..d233511a3a18d1abf9ed873331a263f316ddb080 100644 (file)
@@ -337,11 +337,11 @@ public final class VpnUtil {
     }
 
     static VpnInterfaceOpDataEntry getVpnInterfaceOpDataEntry(String intfName, String vpnName, AdjacenciesOp aug,
-                                                       Uint64 dpnId, long lportTag,
-                                                       String gwMac) {
+                                                              Uint64 dpnId, long lportTag,
+                                                              String gwMac, String gwIp) {
         return new VpnInterfaceOpDataEntryBuilder().withKey(new VpnInterfaceOpDataEntryKey(intfName, vpnName))
-            .setDpnId(dpnId).addAugmentation(AdjacenciesOp.class, aug)
-                .setLportTag(lportTag).setGatewayMacAddress(gwMac).build();
+                .setDpnId(dpnId).addAugmentation(AdjacenciesOp.class, aug)
+                .setLportTag(lportTag).setGatewayMacAddress(gwMac).setGatewayIpAddress(gwIp).build();
     }
 
     Optional<VpnInterfaceOpDataEntry> getVpnInterfaceOpDataEntry(String vpnInterfaceName, String vpnName) {
index a98d999dd7c1eae1e417c67e9fc62a0c265a5f38..81ecb31f034f8acc1573e4ed5b01fb2345b89a53 100644 (file)
@@ -137,6 +137,8 @@ public class ArpResponderHandler {
             ArpReponderInputBuilder builder = new ArpReponderInputBuilder();
             builder.setDpId(dpId.toJava()).setInterfaceName(ifName).setSpa(gatewayIp).setLportTag(lportTag);
             elanService.removeArpResponderFlow(builder.buildForRemoveFlow());
+        } else {
+            LOG.error("Subnet-Gateway-IP is null for interface {}, arpResponderFlow not removed", ifName);
         }
     }