Bug 8145 - DNAT to DNAT traffic is getting failed for 2nd FIP for EVPN/VNI 96/54296/12
authorkarthikeyan <karthikeyan.k@altencalsoftlabs.com>
Tue, 4 Apr 2017 07:44:18 +0000 (13:14 +0530)
committerVivekanandan Narasimhan <n.vivekanandan@ericsson.com>
Sun, 9 Apr 2017 07:18:39 +0000 (07:18 +0000)
Problem Description:
====================
DNAT to DNAT traffic (Different Hypervisor) is getting failed for 2nd FIP
VM for VXLAN and GRE Networks.

Consider 2 FIP VMs are booted on single DPN.

When disassociation/remove of 1st FIP VM, 2nd FIP VM traffic for DNAT to
DNAT is getting failed.

When remove 1st FIP it will remove the flow 36->25 entry. Hence DNAT to
DNAT communication is not happening.

This issue is existing for VXLAN and GRE (L2_L3_VNI Based Forwarding)
external provider type networks only.

Solution:
===========
For EVPN_RT5 and L2-L3 VNI based forwarding, uses "l3vni" value as
tunnel_id in the INTERNAL_TUNNEL_TABLE (table=36). If mutiple FIPs are
existing in the single DPN, each remote tunnel_id will be setting with
same "l3vni" value. Hence removing one FIP is causing the problem
with other DNAT traffic. To avoid this problem added the fix for removing
the flow INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) to
check if any FIP is existing on the given DPN. If not exist then only will
remove the flow table36->25.

Change-Id: I410035b4d160a22ac016a6de3fce219010e6c1f3
Signed-off-by: karthikeyan <karthikeyan.k@altencalsoftlabs.com>
vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang
vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnDnatFlowProgrammer.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java
vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VpnFloatingIpHandler.java
vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang

index 8ebe0b2ed9dc9bbf079ca83fca90bb87f65b39ad..a950f8ca08da54131e0574ffd2fe364dff6b2e10 100644 (file)
@@ -33,6 +33,15 @@ module fib-rpc {
             leaf ip-address {\r
                 type string;\r
             }\r
+            leaf ip-address-source {\r
+                description\r
+                 "This field indicates whether the IP address here is an External-Fixed-Ip(Owned by Router).\r
+                  or Floating-Ip(Used by Ports).";\r
+                type enumeration {\r
+                  enum "ExternalFixedIP";\r
+                  enum "FloatingIP";\r
+                 }\r
+            }\r
             uses offlow:instruction-list;\r
         }\r
     }\r
index 879129ddeecdf7747459be3fd73aff28ee5bde48..f2b03aeda120ca439f37630ae88052a3aeb8a80e 100644 (file)
@@ -22,8 +22,9 @@ import java.util.concurrent.Future;
 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.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
@@ -53,12 +54,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddressesKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstanceKey;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
@@ -95,7 +96,8 @@ public class FibRpcServiceImpl implements FibRpcService {
         List<Instruction> instructions = input.getInstruction();
         LOG.info("ADD: Adding Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
         makeLocalFibEntry(vpnId, dpnId, ipAddress, instructions);
-        updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, vpnName);
+        CreateFibEntryInput.IpAddressSource ipAddressSource = input.getIpAddressSource();
+        updateVpnToDpnAssociation(vpnId, dpnId, ipAddress, ipAddressSource.getIntValue(), vpnName);
         LOG.info("ADD: Added Custom Fib Entry rd {} prefix {} label {}", vpnRd, ipAddress, input.getServiceId());
         return Futures.immediateFuture(RpcResultBuilder.<Void>success().build());
     }
@@ -286,17 +288,21 @@ public class FibRpcServiceImpl implements FibRpcService {
                 + NwConstants.FLOWID_SEPARATOR + ipAddress;
     }
 
-    private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr, String vpnName) {
+    private synchronized void updateVpnToDpnAssociation(long vpnId, BigInteger dpnId, String ipAddr,
+                                                        int ipAddressSourceEnumValue,
+                                                        String vpnName) {
         LOG.debug("Updating VPN to DPN list for dpn : {} for VPN: {} with ip: {}",
             dpnId, vpnName, ipAddr);
         String routeDistinguisher = getVpnRd(dataBroker, vpnName);
         String rd = (routeDistinguisher == null) ? vpnName : routeDistinguisher;
+        IpAddresses.IpAddressSource ipAddressSource = (ipAddressSourceEnumValue == 0)
+                ? IpAddresses.IpAddressSource.ExternalFixedIP : IpAddresses.IpAddressSource.FloatingIP;
         synchronized (vpnName.intern()) {
             InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
             Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
             org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
                 .instance.op.data.entry.vpn.to.dpn.list.IpAddresses ipAddress =
-                new IpAddressesBuilder().setIpAddress(ipAddr).build();
+                new IpAddressesBuilder().setIpAddress(ipAddr).setIpAddressSource(ipAddressSource).build();
 
             if (dpnInVpn.isPresent()) {
                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
@@ -330,25 +336,31 @@ public class FibRpcServiceImpl implements FibRpcService {
             if (dpnInVpn.isPresent()) {
                 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
                     .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses> ipAddresses =
-                    dpnInVpn.get().getIpAddresses();
-                org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn
-                    .instance.op.data.entry.vpn.to.dpn.list.IpAddresses ipAddress =
-                    new IpAddressesBuilder().setIpAddress(ipAddr).build();
-
-                if (ipAddresses != null && ipAddresses.remove(ipAddress)) {
-                    if (ipAddresses.isEmpty()) {
+                        dpnInVpn.get().getIpAddresses();
+                if (ipAddresses != null) {
+                    int ipAddressesSize = ipAddresses.size();
+                    for (IpAddresses ipAddress : ipAddresses) {
+                        if (ipAddress.getIpAddress().equals(ipAddr)) {
+                            ipAddressesSize--;
+                        }
+                    }
+                    if (ipAddressesSize == 0) {
                         List<VpnInterfaces> vpnInterfaces = dpnInVpn.get().getVpnInterfaces();
                         if (vpnInterfaces == null || vpnInterfaces.isEmpty()) {
                             //Clean up the dpn
                             LOG.debug("Cleaning up dpn {} from VPN {}", dpnId, vpnName);
-                            MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+                            try {
+                                SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL,
+                                        id);
+                            } catch (TransactionCommitFailedException e) {
+                                LOG.error("Failed to delete Dpn {} from Vpn-to-Dpn list for Vpn {}", dpnId, vpnName, e);
+                            }
                             fibManager.cleanUpDpnForVpn(dpnId, vpnId, rd, null);
+                        } else {
+                            delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id, dpnId, ipAddr, vpnName);
                         }
                     } else {
-                        delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id.child(
-                            org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
-                                .vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
-                            new IpAddressesKey(ipAddr)));
+                        delete(dataBroker, LogicalDatastoreType.OPERATIONAL, id, dpnId, ipAddr, vpnName);
                     }
                 }
             }
@@ -382,11 +394,18 @@ public class FibRpcServiceImpl implements FibRpcService {
         return new VpnInstanceOpDataEntryBuilder().setVrfId(rd).setVpnId(vpnId).setVpnInstanceName(vpnName).build();
     }
 
-    static <T extends DataObject> void delete(DataBroker broker, LogicalDatastoreType datastoreType,
-                                              InstanceIdentifier<T> path) {
-        WriteTransaction tx = broker.newWriteOnlyTransaction();
-        tx.delete(datastoreType, path);
-        tx.submit();
+    static void delete(DataBroker broker, LogicalDatastoreType datastoreType,
+                                              InstanceIdentifier<VpnToDpnList> id, BigInteger dpnId, String ipAddr,
+                                              String vpnName) {
+        try {
+            SingleTransactionDataBroker.syncDelete(broker,datastoreType,id.child(
+                    org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op
+                            .data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses.class,
+                    new IpAddressesKey(ipAddr)));
+        } catch (TransactionCommitFailedException e) {
+            LOG.error("Failed to delete Ip Address {} from Vpn-to-Dpn list for Dpn : {} for Vpn: {}",
+                    ipAddr, dpnId, vpnName, e);
+        }
     }
 
     static long getVpnId(DataBroker broker, String vpnName) {
index 059f10510084c566968687a19738678ab343f3c2..299f3e273eaa3b53ffb3d641a1006e1b3790cb9c 100644 (file)
@@ -105,23 +105,18 @@ public class EvpnDnatFlowProgrammer {
             LOG.error("NAT Service : Unable to retrieve L3VNI value for Floating IP {} ", externalIp);
             return;
         }
+        long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+        if (vpnId == NatConstants.INVALID_ID) {
+            LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
+            return;
+        }
         FloatingIPListener.updateOperationalDS(dataBroker, routerName, interfaceName, NatConstants.DEFAULT_LABEL_VALUE,
                 internalIp, externalIp);
-        //Inform to FIB
+        //Inform to FIB and BGP
         NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd, externalIp + "/32",
                 nextHopIp, l3Vni, floatingIpInterface, floatingIpPortMacAddress,
                 writeTx, RouteOrigin.STATIC, dpnId);
 
-        List<Instruction> instructions = new ArrayList<>();
-        List<ActionInfo> actionsInfos = new ArrayList<>();
-        List<Instruction> customInstructions = new ArrayList<>();
-        customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
-        actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
-        instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
-        /* Install the Flow table INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25) for SNAT to DNAT
-         * reverse traffic for Non-FIP VM on DPN1 to FIP VM on DPN2
-         */
-        makeTunnelTableEntry(dpnId, l3Vni, instructions);
         /* Install the flow table L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25)
          * (SNAT to DNAT reverse traffic: If the DPN has both SNAT and  DNAT configured )
          */
@@ -132,7 +127,8 @@ public class EvpnDnatFlowProgrammer {
         instructionsFib.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
 
         CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
-                .setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(l3Vni)
+                .setSourceDpid(dpnId).setIpAddress(externalIp + "/32")
+                .setServiceId(l3Vni).setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
                 .setInstruction(instructionsFib).build();
 
         Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
@@ -160,17 +156,28 @@ public class EvpnDnatFlowProgrammer {
                 if (result.isSuccessful()) {
                     LOG.info("NAT Service : Successfully installed custom FIB routes for Floating "
                             + "IP Prefix {} on DPN {}", externalIp, dpnId);
+                    List<Instruction> instructions = new ArrayList<>();
+                    List<ActionInfo> actionsInfos = new ArrayList<>();
+                    List<Instruction> customInstructions = new ArrayList<>();
+                    customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
+                    actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
+                    instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
+                 /* Install the Flow table INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25) for SNAT to DNAT
+                  * reverse traffic for Non-FIP VM on DPN1 to FIP VM on DPN2
+                  */
+                    makeTunnelTableEntry(dpnId, l3Vni, instructions);
+
+                 /* Install the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
+                  * (DNAT reverse traffic: If the traffic is Initiated from DC-GW to FIP VM (DNAT forward traffic))
+                  */
+                    NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, customInstructions,
+                            mdsalManager);
                 } else {
                     LOG.error("NAT Service : Error {} in rpc call to create custom Fib entries for Floating "
                             + "IP Prefix {} on DPN {}, {}", result.getErrors(), externalIp, dpnId);
                 }
             }
         });
-        /* Install the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
-         * (DNAT reverse traffic: If the traffic is Initiated from DC-GW to FIP VM (DNAT forward traffic))
-         */
-        long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
-        NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, customInstructions, mdsalManager);
 
         //Read the FIP vpn-interface details from Configuration l3vpn:vpn-interfaces model and write into Operational DS
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface);
@@ -218,12 +225,14 @@ public class EvpnDnatFlowProgrammer {
             LOG.error("NAT Service : Could not retrieve L3VNI value from RD {} in ", rd);
             return;
         }
+        long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
+        if (vpnId == NatConstants.INVALID_ID) {
+            LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
+            return;
+        }
         //Remove Prefix from BGP
         NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", vpnName, LOG);
 
-       //Remove the flow for INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25)
-        removeTunnelTableEntry(dpnId, l3Vni);
-
         //Remove custom FIB routes flow for L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25)
         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
                 .setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(l3Vni).build();
@@ -242,20 +251,23 @@ public class EvpnDnatFlowProgrammer {
                 if (result.isSuccessful()) {
                     LOG.info("NAT Service : Successfully removed custom FIB routes for Floating "
                             + "IP Prefix {} on DPN {}", externalIp, dpnId);
+                     /*  check if any floating IP information is available in vpn-to-dpn-list for given dpn id.
+                      *  If exist any floating IP then do not remove
+                      *  INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry.
+                      */
+                    if (!NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp)) {
+                        //Remove the flow for INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25)
+                        removeTunnelTableEntry(dpnId, l3Vni);
+                    }
+                    //Remove the flow for L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
+                    NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, mdsalManager);
+
                 } else {
                     LOG.error("NAT Service : Error {} in rpc call to remove custom Fib entries for Floating "
                             + "IP Prefix {} on DPN {}, {}", result.getErrors(), externalIp, dpnId);
                 }
             }
         });
-
-        long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
-        if (vpnId == NatConstants.INVALID_ID) {
-            LOG.warn("NAT Service : Invalid Vpn Id is found for Vpn Name {}", vpnName);
-        }
-        //Remove the flow for L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
-        NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, mdsalManager);
-
         //Read the FIP vpn-interface details from Operational l3vpn:vpn-interfaces model and delete from Operational DS
         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface);
         Optional<VpnInterface> optionalVpnInterface = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
index 937c272ed818fc1b01ee5cd349f44c5c794f7d5d..52b279a7cd3e5a24e74bf5b1f8f9a862bbaeb973 100644 (file)
@@ -1015,6 +1015,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Rou
                         String fibExternalIp = externalIp.contains("/32") ? externalIp : (externalIp + "/32");
                         CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
                             .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
+                            .setIpAddressSource(CreateFibEntryInput.IpAddressSource.ExternalFixedIP)
                             .setInstruction(fibTableCustomInstructions).build();
                         Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
                         return JdkFutureAdapters.listenInPoolThread(future1);
index 662e0a7873ad89fb721a713b7275850d5a0f9dd4..42bd9b5f5233e27525fc1bd85f3b1d9ba1684466 100644 (file)
@@ -116,6 +116,9 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.id.to.vpn.instance.VpnIdsKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntryKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.IpAddresses;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
@@ -1807,4 +1810,33 @@ public class NatUtil {
         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId
                 + NwConstants.FLOWID_SEPARATOR + uniqueId;
     }
+
+    public static Boolean isFloatingIpPresentForDpn(DataBroker dataBroker, BigInteger dpnId, String rd,
+                                                           String vpnName, String externalIp) {
+        InstanceIdentifier<VpnToDpnList> id = getVpnToDpnListIdentifier(rd, dpnId);
+        Optional<VpnToDpnList> dpnInVpn = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
+        if (dpnInVpn.isPresent()) {
+            LOG.debug("vpn-to-dpn-list is not empty for vpnName {}, dpn id {}, rd {} and floatingIp {}",
+                    vpnName, dpnId, rd, externalIp);
+            List<IpAddresses> ipAddressList = dpnInVpn.get().getIpAddresses();
+            if (ipAddressList.size() > 0) {
+                for (IpAddresses ipAddress: ipAddressList) {
+                    if (!ipAddress.getIpAddress().equals(externalIp)
+                            && IpAddresses.IpAddressSource.FloatingIP.equals(ipAddress.getIpAddressSource())) {
+                        return Boolean.TRUE;
+                    }
+                }
+            } else {
+                LOG.debug("vpn-to-dpn-list does not contain any floating IP for DPN {}", dpnId);
+                return Boolean.FALSE;
+            }
+        }
+        return Boolean.FALSE;
+    }
+
+    private static InstanceIdentifier<VpnToDpnList> getVpnToDpnListIdentifier(String rd, BigInteger dpnId) {
+        return InstanceIdentifier.builder(VpnInstanceOpData.class)
+                .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd))
+                .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build();
+    }
 }
index acdc5de7f31a67b2757abca85b55869009ad2ef8..c17fba7e32fb2de08a94e71306bb287950ecc1d2 100644 (file)
@@ -200,6 +200,7 @@ public class VpnFloatingIpHandler implements FloatingIPHandler {
                     CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
                         .setSourceDpid(dpnId).setInstruction(customInstructions)
                         .setIpAddress(externalIp + "/32").setServiceId(label)
+                        .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
                         .setInstruction(customInstructions).build();
                     //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
                     Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
@@ -304,7 +305,18 @@ public class VpnFloatingIpHandler implements FloatingIPHandler {
             (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
                 //Release label
                 if (result.isSuccessful()) {
-                    removeTunnelTableEntry(dpnId, label);
+                /*  check if any floating IP information is available in vpn-to-dpn-list for given dpn id. If exist any
+                 *  floating IP then do not remove INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry
+                 */
+                    Boolean removeTunnelFlow = Boolean.TRUE;
+                    if (nvpnManager.getEnforceOpenstackSemanticsConfig()) {
+                        if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp)) {
+                            removeTunnelFlow = Boolean.FALSE;
+                        }
+                    }
+                    if (removeTunnelFlow) {
+                        removeTunnelTableEntry(dpnId, label);
+                    }
                     removeLFibTableEntry(dpnId, label);
                     RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
                         .setVpnName(vpnName).setIpPrefix(externalIp).build();
index 2597b6bf8034cca9c7d4b8ab717fc42420677a47..cc4ff8c900a6b5059131f852e14d818f65b6a8bf 100644 (file)
@@ -197,6 +197,15 @@ module odl-l3vpn {
                list ip-addresses {
                    key ip-address;
                    leaf ip-address { type string; }
+                   leaf ip-address-source {
+                        description
+                         "This field indicates whether the IP address here is an External-Fixed-Ip(Owned by Router).
+                          or Floating-Ip(Used by Ports).";
+                        type enumeration {
+                            enum "ExternalFixedIP";
+                            enum "FloatingIP";
+                        }
+                   }
                }
                leaf dpn-state {
                   description