From: karthikeyan Date: Tue, 4 Apr 2017 07:44:18 +0000 (+0530) Subject: Bug 8145 - DNAT to DNAT traffic is getting failed for 2nd FIP for EVPN/VNI X-Git-Tag: release/carbon~114 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=b3b933efc76652d932ddc07a94b9069513d3ce05;p=netvirt.git Bug 8145 - DNAT to DNAT traffic is getting failed for 2nd FIP for EVPN/VNI 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 --- diff --git a/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang b/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang index 8ebe0b2ed9..a950f8ca08 100644 --- a/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang +++ b/vpnservice/fibmanager/fibmanager-api/src/main/yang/fib-rpc.yang @@ -33,6 +33,15 @@ module fib-rpc { 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"; + } + } uses offlow:instruction-list; } } diff --git a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java index 879129ddee..f2b03aeda1 100644 --- a/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java +++ b/vpnservice/fibmanager/fibmanager-impl/src/main/java/org/opendaylight/netvirt/fibmanager/FibRpcServiceImpl.java @@ -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 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.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 id = getVpnToDpnListIdentifier(rd, dpnId); Optional 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 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 = 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 void delete(DataBroker broker, LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.delete(datastoreType, path); - tx.submit(); + static void delete(DataBroker broker, LogicalDatastoreType datastoreType, + InstanceIdentifier 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) { diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnDnatFlowProgrammer.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnDnatFlowProgrammer.java index 059f105100..299f3e273e 100644 --- a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnDnatFlowProgrammer.java +++ b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/EvpnDnatFlowProgrammer.java @@ -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 instructions = new ArrayList<>(); - List actionsInfos = new ArrayList<>(); - List 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> 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 instructions = new ArrayList<>(); + List actionsInfos = new ArrayList<>(); + List 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 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 vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface); Optional optionalVpnInterface = NatUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java index 937c272ed8..52b279a7cd 100644 --- a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java +++ b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/ExternalRoutersListener.java @@ -1015,6 +1015,7 @@ public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase> future1 = fibService.createFibEntry(input); return JdkFutureAdapters.listenInPoolThread(future1); diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java index 662e0a7873..42bd9b5f52 100644 --- a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java +++ b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/NatUtil.java @@ -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 id = getVpnToDpnListIdentifier(rd, dpnId); + Optional 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 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 getVpnToDpnListIdentifier(String rd, BigInteger dpnId) { + return InstanceIdentifier.builder(VpnInstanceOpData.class) + .child(VpnInstanceOpDataEntry.class, new VpnInstanceOpDataEntryKey(rd)) + .child(VpnToDpnList.class, new VpnToDpnListKey(dpnId)).build(); + } } diff --git a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VpnFloatingIpHandler.java b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VpnFloatingIpHandler.java index acdc5de7f3..c17fba7e32 100644 --- a/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VpnFloatingIpHandler.java +++ b/vpnservice/natservice/natservice-impl/src/main/java/org/opendaylight/netvirt/natservice/internal/VpnFloatingIpHandler.java @@ -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> createFibEntry(CreateFibEntryInput input); Future> future1 = fibService.createFibEntry(input); @@ -304,7 +305,18 @@ public class VpnFloatingIpHandler implements FloatingIPHandler { (AsyncFunction, RpcResult>) 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(); diff --git a/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang index 2597b6bf80..cc4ff8c900 100644 --- a/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang +++ b/vpnservice/vpnmanager/vpnmanager-api/src/main/yang/odl-l3vpn.yang @@ -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