Remove NatUtil::read()
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / VpnFloatingIpHandler.java
index 94a3fe18d753933841f61f59d272002ffc6cdc4e..962665d234d20dd7890da2a364041b65bae1d949 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
+ * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
@@ -7,37 +7,48 @@
  */
 package org.opendaylight.netvirt.natservice.internal;
 
+import static org.opendaylight.netvirt.natservice.internal.NatUtil.buildfloatingIpIdToPortMappingIdentifier;
+
+import com.google.common.base.Optional;
 import com.google.common.util.concurrent.AsyncFunction;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.JdkFutureAdapters;
 import com.google.common.util.concurrent.ListenableFuture;
-
 import java.math.BigInteger;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 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.genius.datastoreutils.SingleTransactionDataBroker;
 import org.opendaylight.genius.mdsalutil.ActionInfo;
-import org.opendaylight.genius.mdsalutil.ActionType;
-import org.opendaylight.genius.mdsalutil.InstructionInfo;
-import org.opendaylight.genius.mdsalutil.InstructionType;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.genius.mdsalutil.MatchFieldType;
 import org.opendaylight.genius.mdsalutil.MatchInfo;
 import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
+import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
+import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
+import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
+import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
+import org.opendaylight.netvirt.elanmanager.api.IElanService;
 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
-import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
+import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
+import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
-import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
@@ -46,22 +57,28 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.Se
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@Singleton
 public class VpnFloatingIpHandler implements FloatingIPHandler {
     private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
     private final DataBroker dataBroker;
@@ -69,94 +86,141 @@ public class VpnFloatingIpHandler implements FloatingIPHandler {
     private final VpnRpcService vpnService;
     private final IBgpManager bgpManager;
     private final FibRpcService fibService;
-    private final FloatingIPListener floatingIPListener;
     private final IVpnManager vpnManager;
     private final IFibManager fibManager;
     private final OdlArputilService arpUtilService;
-    static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
-    static final String FLOWID_PREFIX = "NAT.";
-
+    private final IElanService elanService;
+    private final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer;
+    private final INeutronVpnManager nvpnManager;
+    private final IdManagerService idManager;
+    private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
+    private static final String FLOWID_PREFIX = "NAT.";
+
+    @Inject
     public VpnFloatingIpHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
                                 final VpnRpcService vpnService,
                                 final IBgpManager bgpManager,
                                 final FibRpcService fibService,
-                                final FloatingIPListener floatingIPListener,
                                 final IFibManager fibManager,
                                 final OdlArputilService arputilService,
-                                final IVpnManager vpnManager) {
+                                final IVpnManager vpnManager,
+                                final IElanService elanService,
+                                final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer,
+                                final INeutronVpnManager nvpnManager,
+                                final IdManagerService idManager) {
         this.dataBroker = dataBroker;
         this.mdsalManager = mdsalManager;
         this.vpnService = vpnService;
         this.bgpManager = bgpManager;
         this.fibService = fibService;
-        this.floatingIPListener = floatingIPListener;
         this.fibManager = fibManager;
         this.arpUtilService = arputilService;
         this.vpnManager = vpnManager;
+        this.elanService = elanService;
+        this.evpnDnatFlowProgrammer = evpnDnatFlowProgrammer;
+        this.nvpnManager = nvpnManager;
+        this.idManager = idManager;
     }
 
     @Override
     public void onAddFloatingIp(final BigInteger dpnId, final String routerId,
-                                Uuid networkId, final String interfaceName, final String externalIp,
-                                final String internalIp) {
-        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+                                final Uuid networkId, final String interfaceName,
+                                final InternalToExternalPortMap mapping) {
+        String externalIp = mapping.getExternalIp();
+        String internalIp = mapping.getInternalIp();
+        Uuid floatingIpId = mapping.getExternalId();
+        Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpId);
+        String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
+        Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, subnetId);
+        final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
+            NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+        final String subnetVpnName = externalSubnet.isPresent() ? subnetId.getValue() : null;
         if (vpnName == null) {
             LOG.info("No VPN associated with ext nw {} to handle add floating ip configuration {} in router {}",
-                    networkId, externalIp, routerId);
+                networkId, externalIp, routerId);
+            return;
+        }
+        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
+        String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
+        LOG.debug("Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
+        WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+        ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerId);
+        if (provType == null) {
+            return;
+        }
+        NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
+                NatConstants.ODL_VNI_POOL_NAME);
+        if (provType == ProviderTypes.VXLAN) {
+            Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
+            evpnDnatFlowProgrammer.onAddFloatingIp(dpnId, routerId, vpnName, internalIp, externalIp, networkId,
+                    interfaceName, floatingIpInterface.getValue(), floatingIpPortMacAddress, rd, nextHopIp, writeTx);
+            if (writeTx != null) {
+                writeTx.submit();
+            }
             return;
         }
-
         GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
-                .setIpPrefix(externalIp).build();
+            .setIpPrefix(externalIp).build();
         Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
 
-        ListenableFuture<RpcResult<Void>> future = Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture),
-                new AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>() {
-
-            @Override
-            public ListenableFuture<RpcResult<Void>> apply(RpcResult<GenerateVpnLabelOutput> result) throws Exception {
-                if(result.isSuccessful()) {
+        ListenableFuture<RpcResult<Void>> future = Futures.transformAsync(
+                JdkFutureAdapters.listenInPoolThread(labelFuture),
+                (AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>) result -> {
+                if (result.isSuccessful()) {
                     GenerateVpnLabelOutput output = result.getResult();
                     long label = output.getLabel();
                     LOG.debug("Generated label {} for prefix {}", label, externalIp);
-                    floatingIPListener.updateOperationalDS(routerId, interfaceName, label, internalIp, externalIp);
-
+                    FloatingIPListener.updateOperationalDS(dataBroker, routerId, interfaceName, label,
+                        internalIp, externalIp);
                     //Inform BGP
-                    String rd = NatUtil.getVpnRd(dataBroker, vpnName);
-                    String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
-                    LOG.debug("Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
-                    NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", nextHopIp,
-                            label, LOG, RouteOrigin.STATIC);
+                    long l3vni = 0;
+                    if (elanService.isOpenStackVniSemanticsEnforced()) {
+                        l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
+                    }
+                    String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
+                    NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, subnetId,
+                            fibExternalIp, nextHopIp, networkId.getValue(), floatingIpPortMacAddress,
+                            label, l3vni, LOG, RouteOrigin.STATIC, dpnId);
 
                     List<Instruction> instructions = new ArrayList<>();
                     List<ActionInfo> actionsInfos = new ArrayList<>();
-                    actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NwConstants.PDNAT_TABLE) }));
-                    instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0));
-                    makeTunnelTableEntry(dpnId, label, instructions);
+                    actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
+                    instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
+                    makeTunnelTableEntry(vpnName, dpnId, label, instructions);
 
                     //Install custom FIB routes
+                    List<ActionInfo> actionInfoFib = new ArrayList<>();
                     List<Instruction> customInstructions = new ArrayList<>();
-                    customInstructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.PDNAT_TABLE }).buildInstruction(0));
-                    makeLFibTableEntry(dpnId, label, NwConstants.PDNAT_TABLE);
-                    CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setInstruction(customInstructions)
-                            .setIpAddress(externalIp + "/32").setServiceId(label).setInstruction(customInstructions).build();
+                    actionInfoFib.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
+                    customInstructions.add(new InstructionApplyActions(actionInfoFib).buildInstruction(0));
+                    customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
+
+                    makeLFibTableEntry(dpnId, label, floatingIpPortMacAddress, NwConstants.PDNAT_TABLE);
+                    CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
+                        .setSourceDpid(dpnId).setInstruction(customInstructions)
+                        .setIpAddress(fibExternalIp).setServiceId(label)
+                        .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
+                        .setInstruction(customInstructions).build();
                     //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
-                    Future<RpcResult<Void>> future = fibService.createFibEntry(input);
-                    WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
-                    IpAddress externalIpAddress = new IpAddress(new Ipv4Address(externalIp));
-                    Port neutronPort = NatUtil.getNeutronPortForFloatingIp(dataBroker, externalIpAddress);
-                    if (neutronPort != null && neutronPort.getMacAddress() != null) {
-                        vpnManager.setupSubnetMacIntoVpnInstance(vpnName, neutronPort.getMacAddress().getValue(), writeTx, NwConstants.ADD_FLOW);
+                    Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
+                    LOG.debug("Add Floating Ip {} , found associated to fixed port {}", externalIp, interfaceName);
+                    if (floatingIpPortMacAddress != null) {
+                        String networkVpnName =  NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+                        vpnManager.setupSubnetMacIntoVpnInstance(networkVpnName, subnetVpnName,
+                                floatingIpPortMacAddress, dpnId, writeTx, NwConstants.ADD_FLOW);
+                        vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerId,
+                                Collections.singleton(externalIp),
+                            floatingIpPortMacAddress, dpnId, networkId, writeTx, NwConstants.ADD_FLOW);
+                        writeTx.submit();
                     }
-                    writeTx.submit();
-                    return JdkFutureAdapters.listenInPoolThread(future);
+                    return JdkFutureAdapters.listenInPoolThread(future1);
                 } else {
-                    String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s", externalIp, vpnName, result.getErrors());
+                    String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
+                        externalIp, vpnName, result.getErrors());
                     LOG.error(errMsg);
                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
                 }
-            }
-        });
+            });
 
         Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
 
@@ -167,121 +231,107 @@ public class VpnFloatingIpHandler implements FloatingIPHandler {
 
             @Override
             public void onSuccess(RpcResult<Void> result) {
-                if(result.isSuccessful()) {
+                if (result.isSuccessful()) {
                     LOG.info("Successfully installed custom FIB routes for prefix {}", externalIp);
                 } else {
-                    LOG.error("Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}", externalIp, dpnId, result.getErrors());
+                    LOG.error("Error in rpc call to create custom Fib entries for prefix {} in DPN {}, {}",
+                        externalIp, dpnId, result.getErrors());
                 }
             }
         });
 
         // Handle GARP transmission
         final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
-        final IpAddress internalAddress = IpAddressBuilder.getDefaultInstance(internalIp);
-        Port neutronPortForIp = NatUtil.getNeutronPortForIp(dataBroker,internalAddress,
-                NeutronConstants.DEVICE_OWNER_NEUTRON_PORT);
-        if (neutronPortForIp == null) {
-            LOG.warn("No neutron port was found for external ip {} in router {}", internalIp, routerId);
-            NatServiceCounters.port_not_found_for_floating.inc();
-            return;
-        }
-        sendGarpOnInterface(neutronPortForIp.getUuid().getValue(), extrenalAddress, routerId);
+        sendGarpOnInterface(dpnId, networkId, extrenalAddress, floatingIpPortMacAddress);
 
     }
 
     @Override
-    public void onRemoveFloatingIp(final BigInteger dpnId, String routerId, Uuid networkId, final String externalIp,
-                                   String internalIp, final long label) {
-        final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+    public void onRemoveFloatingIp(final BigInteger dpnId, String routerId, final Uuid networkId,
+                                   InternalToExternalPortMap mapping, final long label) {
+        String externalIp = mapping.getExternalIp();
+        Uuid floatingIpId = mapping.getExternalId();
+        Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpId);
+        Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, subnetId);
+        final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
+            NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
         if (vpnName == null) {
             LOG.info("No VPN associated with ext nw {} to handle remove floating ip configuration {} in router {}",
-                    networkId, externalIp, routerId);
+                networkId, externalIp, routerId);
             return;
         }
+
         //Remove floating mac from mymac table
-        WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
-        IpAddress externalIpAddress = new IpAddress(new Ipv4Address(externalIp));
-        Port neutronPort = NatUtil.getNeutronPortForFloatingIp(dataBroker, externalIpAddress);
-        if (neutronPort != null && neutronPort.getMacAddress() != null) {
-            vpnManager.setupSubnetMacIntoVpnInstance(vpnName, neutronPort.getMacAddress().getValue(), writeTx, NwConstants.DEL_FLOW);
+        LOG.debug("Removing FloatingIp {}", externalIp);
+        String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
+        if (floatingIpPortMacAddress != null) {
+            WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+            String networkVpnName =  NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
+            vpnManager.setupSubnetMacIntoVpnInstance(networkVpnName, subnetId.getValue(), floatingIpPortMacAddress,
+                    dpnId, writeTx, NwConstants.DEL_FLOW);
+            vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerId, Collections.singletonList(externalIp),
+                floatingIpPortMacAddress, dpnId, networkId, writeTx, NwConstants.DEL_FLOW);
+            writeTx.submit();
         }
-        writeTx.submit();
-        //Remove Prefix from BGP
-        String rd = NatUtil.getVpnRd(dataBroker, vpnName);
-        NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
-
-        //Remove custom FIB routes
-        //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
-        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
-        Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
-
-        ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future), new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
-
-            @Override
-            public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
-                //Release label
-                if(result.isSuccessful()) {
-                    removeTunnelTableEntry(dpnId, label);
-                    removeLFibTableEntry(dpnId, label);
-                    RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
-                    Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
-                    return JdkFutureAdapters.listenInPoolThread(labelFuture);
-                } else {
-                    String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
-                    LOG.error(errMsg);
-                    return Futures.immediateFailedFuture(new RuntimeException(errMsg));
-                }
-            }
-        });
-
-        Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
-
-            @Override
-            public void onFailure(Throwable error) {
-                LOG.error("Error in removing the label or custom fib entries", error);
-            }
-
-            @Override
-            public void onSuccess(RpcResult<Void> result) {
-                if(result.isSuccessful()) {
-                    LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
-                } else {
-                    LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
-                }
-            }
-        });
+        removeFromFloatingIpPortInfo(floatingIpId);
+        ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerId);
+        if (provType == null) {
+            return;
+        }
+        if (provType == ProviderTypes.VXLAN) {
+            Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
+            evpnDnatFlowProgrammer.onRemoveFloatingIp(dpnId, vpnName, externalIp, floatingIpInterface.getValue(),
+                    floatingIpPortMacAddress, routerId);
+            return;
+        }
+        cleanupFibEntries(dpnId, vpnName, externalIp, label);
     }
 
-    void cleanupFibEntries(final BigInteger dpnId, final String vpnName, final String externalIp, final long label ) {
+    @Override
+    public void cleanupFibEntries(final BigInteger dpnId, final String vpnName, final String externalIp,
+                                  final long label) {
         //Remove Prefix from BGP
         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
-        NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp + "/32", LOG);
+        String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
+        NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, fibExternalIp, vpnName, LOG);
 
         //Remove custom FIB routes
 
         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
-        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp + "/32").setServiceId(label).build();
+        RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
+            .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
+            .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
 
-        ListenableFuture<RpcResult<Void>> labelFuture = Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
-            new AsyncFunction<RpcResult<Void>, RpcResult<Void>>() {
-
-            @Override
-            public ListenableFuture<RpcResult<Void>> apply(RpcResult<Void> result) throws Exception {
+        ListenableFuture<RpcResult<Void>> labelFuture = Futures.transformAsync(
+                JdkFutureAdapters.listenInPoolThread(future),
+                (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
                 //Release label
-                if(result.isSuccessful()) {
-                    removeTunnelTableEntry(dpnId, label);
+                if (result.isSuccessful()) {
+                /*  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 (elanService.isOpenStackVniSemanticsEnforced()) {
+                        if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp, false)) {
+                            removeTunnelFlow = Boolean.FALSE;
+                        }
+                    }
+                    if (removeTunnelFlow) {
+                        removeTunnelTableEntry(dpnId, label);
+                    }
                     removeLFibTableEntry(dpnId, label);
-                    RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
-                    Future<RpcResult<Void>> labelFuture = vpnService.removeVpnLabel(labelInput);
-                    return JdkFutureAdapters.listenInPoolThread(labelFuture);
+                    RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
+                        .setVpnName(vpnName).setIpPrefix(externalIp).build();
+                    Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
+                    return JdkFutureAdapters.listenInPoolThread(labelFuture1);
                 } else {
-                    String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
+                    String errMsg = String.format("RPC call to remove custom FIB entries on dpn %s for "
+                        + "prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
                     LOG.error(errMsg);
                     return Futures.immediateFailedFuture(new RuntimeException(errMsg));
                 }
-            }
-        });
+            });
 
         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
 
@@ -292,116 +342,153 @@ public class VpnFloatingIpHandler implements FloatingIPHandler {
 
             @Override
             public void onSuccess(RpcResult<Void> result) {
-                if(result.isSuccessful()) {
+                if (result.isSuccessful()) {
                     LOG.debug("Successfully removed the label for the prefix {} from VPN {}", externalIp, vpnName);
                 } else {
-                    LOG.error("Error in removing the label for prefix {} from VPN {}, {}", externalIp, vpnName, result.getErrors());
+                    LOG.error("Error in removing the label for prefix {} from VPN {}, {}",
+                        externalIp, vpnName, result.getErrors());
                 }
             }
         });
     }
 
     private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
-        return new StringBuilder(64).append(FLOWID_PREFIX).append(dpnId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(tableId).append(NwConstants.FLOWID_SEPARATOR)
-                .append(id).append(NwConstants.FLOWID_SEPARATOR).append(ipAddress).toString();
+        return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + id
+                + NwConstants.FLOWID_SEPARATOR + ipAddress;
     }
 
     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
-        LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId , serviceId);
+        LOG.info("remove terminatingServiceActions called with DpnId = {} and label = {}", dpnId, serviceId);
         List<MatchInfo> mkMatches = new ArrayList<>();
         // Matching metadata
-        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+        mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
-                5, String.format("%s:%d","TST Flow Entry ",serviceId), 0, 0,
-                COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
+            getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
+            5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
+            COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
         mdsalManager.removeFlow(dpnId, flowEntity);
-        LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}",dpnId, serviceId);
+        LOG.debug("Terminating service Entry for dpID {} : label : {} removed successfully {}", dpnId, serviceId);
     }
 
-    private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
+    private void makeTunnelTableEntry(String vpnName, BigInteger dpnId, long serviceId,
+            List<Instruction> customInstructions) {
         List<MatchInfo> mkMatches = new ArrayList<>();
 
-        LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId , serviceId);
-
-        mkMatches.add(new MatchInfo(MatchFieldType.tunnel_id, new BigInteger[] {BigInteger.valueOf(serviceId)}));
+        LOG.info("create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}", dpnId, serviceId);
+        int flowPriority = 5;
+        // Increased the 36->25 flow priority. If SNAT is also configured on the same
+        // DPN, then the traffic will be hijacked to DNAT and if there are no DNAT match,
+        // then handled back to using using flow 25->44(which will be installed as part of SNAT)
+        if (elanService.isOpenStackVniSemanticsEnforced()) {
+            mkMatches.add(new MatchTunnelId(NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, serviceId)));
+            flowPriority = 6;
+        } else {
+            mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
+        }
 
         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
-                getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5, String.format("%s:%d","TST Flow Entry ",serviceId),
-                0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)),mkMatches, customInstructions);
+            getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), flowPriority,
+            String.format("%s:%d", "TST Flow Entry ", serviceId),
+            0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
 
         mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
     }
 
-    private void makeLFibTableEntry(BigInteger dpId, long serviceId, long tableId) {
+    private void makeLFibTableEntry(BigInteger dpId, long serviceId, String floatingIpPortMacAddress, short tableId) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.eth_type,
-                new long[] { 0x8847L }));
-        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+        matches.add(MatchEthernetType.MPLS_UNICAST);
+        matches.add(new MatchMplsLabel(serviceId));
 
         List<Instruction> instructions = new ArrayList<>();
         List<ActionInfo> actionsInfos = new ArrayList<>();
-        actionsInfos.add(new ActionInfo(ActionType.pop_mpls, new String[]{}));
-        Instruction writeInstruction = new InstructionInfo(InstructionType.apply_actions, actionsInfos).buildInstruction(0);
+        actionsInfos.add(new ActionPopMpls());
+        actionsInfos.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
+        Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
         instructions.add(writeInstruction);
-        instructions.add(new InstructionInfo(InstructionType.goto_table, new long[]{tableId}).buildInstruction(1));
+        instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
 
         // Install the flow entry in L3_LFIB_TABLE
         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
 
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
-                10, flowRef, 0, 0,
-                NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
+            10, flowRef, 0, 0,
+            NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
 
         mdsalManager.installFlow(dpId, flowEntity);
 
-        LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}",dpId, serviceId );
+        LOG.debug("LFIB Entry for dpID {} : label : {} modified successfully {}", dpId, serviceId);
     }
 
     private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
         List<MatchInfo> matches = new ArrayList<>();
-        matches.add(new MatchInfo(MatchFieldType.eth_type,
-                                  new long[] { 0x8847L }));
-        matches.add(new MatchInfo(MatchFieldType.mpls_label, new String[]{Long.toString(serviceId)}));
+        matches.add(MatchEthernetType.MPLS_UNICAST);
+        matches.add(new MatchMplsLabel(serviceId));
 
         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
 
         LOG.debug("removing LFib entry with flow ref {}", flowRef);
 
         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
-                                               10, flowRef, 0, 0,
-                                               NwConstants.COOKIE_VM_LFIB_TABLE, matches, null);
+            10, flowRef, 0, 0,
+            NwConstants.COOKIE_VM_LFIB_TABLE, matches, null);
 
         mdsalManager.removeFlow(dpnId, flowEntity);
 
-        LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}",dpnId, serviceId);
+        LOG.debug("LFIB Entry for dpID : {} label : {} removed successfully {}", dpnId, serviceId);
     }
 
-    private void sendGarpOnInterface(String interfaceName, final IpAddress floatingIpAddress, final String routerId) {
+    // TODO Clean up the exception handling
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void sendGarpOnInterface(final BigInteger dpnId, Uuid networkId, final IpAddress floatingIpAddress,
+                                     String floatingIpPortMacAddress) {
         if (floatingIpAddress.getIpv4Address() == null) {
-            LOG.warn("Faild to send GARP for IP. recieved IPv6.");
-            NatServiceCounters.garp_sent_ipv6.inc();
+            LOG.info("Failed to send GARP for IP. recieved IPv6.");
+            NatServiceCounters.garp_failed_ipv6.inc();
             return;
         }
 
+        String interfaceName = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
+        if (interfaceName == null) {
+            LOG.warn("Failed to send GARP for IP. Failed to retrieve interface name from network {} and dpn id {}.",
+                networkId.getValue(), dpnId);
+            NatServiceCounters.garp_failed_missing_interface.inc();
+        }
+
         try {
-            Port floatingPort = NatUtil.getNeutronPortForFloatingIp(dataBroker, floatingIpAddress);
-            PhysAddress floatingPortMac = new PhysAddress(floatingPort.getMacAddress().getValue());
+            // find the external network interface name for dpn
             List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
             interfaceAddresses.add(new InterfaceAddressBuilder()
-                    .setInterface(interfaceName)
-                    .setIpAddress(floatingIpAddress)
-                    .setMacaddress(floatingPortMac).build());
+                .setInterface(interfaceName)
+                .setIpAddress(floatingIpAddress)
+                .setMacaddress(new PhysAddress(floatingIpPortMacAddress)).build());
 
             SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
-                    .setInterfaceAddress(interfaceAddresses).build();
+                .setInterfaceAddress(interfaceAddresses).build();
             arpUtilService.sendArpRequest(sendArpRequestInput);
             NatServiceCounters.garp_sent.inc();
         } catch (Exception e) {
             LOG.error("Failed to send GARP request for floating ip {} from interface {}",
-                    floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
-            NatServiceCounters.garp_sent_failed.inc();
+                floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
+            NatServiceCounters.garp_failed_send.inc();
+        }
+    }
+
+    // TODO Clean up the exception handling
+    @SuppressWarnings("checkstyle:IllegalCatch")
+    private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
+        InstanceIdentifier id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
+        try {
+            Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping =
+                    SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
+                            LogicalDatastoreType.CONFIGURATION, id);
+            if (optFloatingIpIdToPortMapping.isPresent() && optFloatingIpIdToPortMapping.get().isFloatingIpDeleted()) {
+                LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
+                    + "IP Port Info Config DS", floatingIpId.getValue());
+                MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
+            }
+        } catch (Exception e) {
+            LOG.error("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
+                + "IP Port Info Config DS failed with exception {}", floatingIpId.getValue(), e);
         }
     }