Action redesign: use the new ActionInfo Genius classes
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NaptEventHandler.java
index e9532c59991537dff2230990fad0e9781eea032d..dd72e862b2061d80bb0617b0a3df363872b9abad 100644 (file)
@@ -8,38 +8,81 @@
 
 package org.opendaylight.netvirt.natservice.internal;
 
-import org.opendaylight.genius.mdsalutil.*;
-import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
-import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.liblldp.NetUtils;
+import org.opendaylight.controller.liblldp.PacketException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
+import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
+import org.opendaylight.genius.mdsalutil.ActionInfo;
+import org.opendaylight.genius.mdsalutil.FlowEntity;
+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.MetaDataUtil;
+import org.opendaylight.genius.mdsalutil.NwConstants;
+import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
+import org.opendaylight.genius.mdsalutil.actions.ActionPushVlan;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldVlanVid;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetTcpDestinationPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetTcpSourcePort;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetUdpDestinationPort;
+import org.opendaylight.genius.mdsalutil.actions.ActionSetUdpSourcePort;
+import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
+import org.opendaylight.genius.mdsalutil.packet.Ethernet;
+import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
+import org.opendaylight.genius.mdsalutil.packet.IPv4;
+import org.opendaylight.genius.mdsalutil.packet.TCP;
+import org.opendaylight.genius.mdsalutil.packet.UDP;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+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.Uuid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class NaptEventHandler {
-    private NaptManager naptManager;
     private static final Logger LOG = LoggerFactory.getLogger(NaptEventHandler.class);
+    private final DataBroker dataBroker;
     private static IMdsalApiManager mdsalManager;
-    private DataBroker dataBroker;
-
-    public NaptEventHandler(final DataBroker dataBroker) {
+    private final PacketProcessingService pktService;
+    private final OdlInterfaceRpcService interfaceManagerRpc;
+    private final NaptManager naptManager;
+    private IInterfaceManager interfaceManager;
+
+    public NaptEventHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
+                            final NaptManager naptManager,
+                            final PacketProcessingService pktService,
+                            final OdlInterfaceRpcService interfaceManagerRpc,
+                            final IInterfaceManager interfaceManager) {
         this.dataBroker = dataBroker;
-    }
-
-    public void setMdsalManager(IMdsalApiManager mdsalManager) {
-        this.mdsalManager = mdsalManager;
-    }
-
-    public void setNaptManager(NaptManager naptManager) {
+        NaptEventHandler.mdsalManager = mdsalManager;
         this.naptManager = naptManager;
+        this.pktService = pktService;
+        this.interfaceManagerRpc = interfaceManagerRpc;
+        this.interfaceManager = interfaceManager;
     }
 
-
     public void handleEvent(NAPTEntryEvent naptEntryEvent){
     /*
             Flow programming logic of the OUTBOUND NAPT TABLE :
@@ -60,9 +103,17 @@ public class NaptEventHandler {
             3) Write the router ID to the metadata.
             5) Write the flow to the INBOUND NAPT Table and forward to FIB table for routing the traffic.
     */
+        try {
         Long routerId = naptEntryEvent.getRouterId();
         LOG.info("NAT Service : handleEvent() entry for IP {}, port {}, routerID {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
-
+        // Get the External Gateway MAC Address
+        String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
+        if (extGwMacAddress != null) {
+            LOG.debug("NAT Service : External Gateway MAC address {} found for External Router ID {}", extGwMacAddress, routerId);
+        } else {
+           LOG.error("NAT Service : No External Gateway MAC address found for External Router ID {}", routerId);
+           return;
+        }
         //Get the DPN ID
         BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
         long bgpVpnId = NatConstants.INVALID_ID;
@@ -71,7 +122,11 @@ public class NaptEventHandler {
             bgpVpnId = routerId;
             LOG.debug("NAT Service : BGP VPN ID {}", bgpVpnId);
             String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
-            String routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
+            String routerName = NatUtil.getRouterIdfromVpnInstance(dataBroker, vpnName);
+            if (routerName == null) {
+                LOG.error("NAT Service: Unable to find router for VpnName {}", vpnName);
+                return;
+            }
             routerId = NatUtil.getVpnId(dataBroker, routerName);
             LOG.debug("NAT Service : Router ID {}", routerId);
             dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
@@ -112,28 +167,104 @@ public class NaptEventHandler {
                     return;
                 }
             }
-            //Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
-            buildAndInstallNatFlows(dpnId, NatConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, internalAddress, externalAddress, protocol);
-            buildAndInstallNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, externalAddress, internalAddress, protocol);
+             // Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
+            if (!naptEntryEvent.isPktProcessed()) {
+                // Added External Gateway MAC Address
+                buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId,
+                        internalAddress, externalAddress, protocol, extGwMacAddress);
+                buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId,
+                        externalAddress, internalAddress, protocol, extGwMacAddress);
+            }
+
+            //Send Packetout - tcp or udp packets which got punted to controller.
+            BigInteger metadata = naptEntryEvent.getPacketReceived().getMatch().getMetadata().getMetadata();
+            byte[] inPayload = naptEntryEvent.getPacketReceived().getPayload();
+            Ethernet ethPkt = new Ethernet();
+            if (inPayload != null) {
+                try {
+                    ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
+                } catch (Exception e) {
+                    LOG.warn("NAT Service : Failed to decode Packet", e);
+                    return;
+                }
+            }
+
+
+            long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
+            LOG.debug("NAT Service : portTag from incoming packet is {}", portTag);
+            String interfaceName = getInterfaceNameFromTag(portTag);
+            LOG.debug("NAT Service : interfaceName fetched from portTag is {}", interfaceName);
+            org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = null;
+            int vlanId = 0;
+            iface = interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
+            if(iface == null) {
+                LOG.error("NAT Service : Unable to read interface {} from config DataStore", interfaceName);
+                return;
+            }
+            IfL2vlan ifL2vlan = iface.getAugmentation(IfL2vlan.class);
+            if(ifL2vlan != null && ifL2vlan.getVlanId() !=null){
+                vlanId = ifL2vlan.getVlanId().getValue() == null ? 0 : ifL2vlan.getVlanId().getValue();
+            }
+            InterfaceInfo infInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
+            if(infInfo !=null) {
+                LOG.debug("NAT Service : portName fetched from interfaceManager is {}", infInfo.getPortName());
+            }
+
+            byte[] pktOut = buildNaptPacketOut(ethPkt);
+
+            List<ActionInfo> actionInfos  = new ArrayList<ActionInfo>();
+            if (ethPkt.getPayload() instanceof IPv4) {
+                IPv4 ipPkt = (IPv4) ethPkt.getPayload();
+                if ((ipPkt.getPayload() instanceof TCP) || (ipPkt.getPayload() instanceof UDP) ) {
+                    if (ethPkt.getEtherType() != (short)NwConstants.ETHTYPE_802_1Q) {
+                        // VLAN Access port
+                        if(infInfo != null) {
+                            LOG.debug("NAT Service : vlanId is {}", vlanId);
+                            if(vlanId != 0) {
+                                // Push vlan
+                                actionInfos.add(new ActionPushVlan(0));
+                                actionInfos.add(new ActionSetFieldVlanVid(1, vlanId));
+                            } else {
+                                LOG.debug("NAT Service : No vlanId {}, may be untagged", vlanId);
+                            }
+                        } else {
+                            LOG.error("NAT Service : error in getting interfaceInfo");
+                            return;
+                        }
+                    } else {
+                        // VLAN Trunk Port
+                        LOG.debug("NAT Service : This is VLAN Trunk port case - need not do VLAN tagging again");
+                    }
+                }
+            }
+            if(pktOut != null) {
+                sendNaptPacketOut(pktOut, infInfo, actionInfos, routerId);
+            } else {
+                LOG.warn("NAT Service : Unable to send Packet Out");
+            }
 
         }else{
             LOG.debug("NAT Service : Inside delete Operation of NaptEventHandler");
-            removeNatFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
+            removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
         }
 
-        LOG.info("NAT Service : handleNaptEvent() exited for IP, port, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+        LOG.info("NAT Service : handleNaptEvent() exited for IP {}, port {}, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
+        } catch (Exception e){
+            LOG.error("NAT Service :Exception in NaptEventHandler.handleEvent() payload {}", naptEntryEvent,e);
+        }
     }
 
-    public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId, long bgpVpnId, SessionAddress actualSourceAddress,
-                                         SessionAddress translatedSourceAddress, NAPTEntryEvent.Protocol protocol){
+    public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId,
+                                               long bgpVpnId, SessionAddress actualSourceAddress, SessionAddress translatedSourceAddress,
+                                               NAPTEntryEvent.Protocol protocol, String extGwMacAddress) {
         LOG.debug("NAT Service : Build and install NAPT flows in InBound and OutBound tables for dpnId {} and routerId {}", dpnId, routerId);
         //Build the flow for replacing the actual IP and port with the translated IP and port.
         String actualIp = actualSourceAddress.getIpAddress();
         int actualPort = actualSourceAddress.getPortNumber();
         String translatedIp = translatedSourceAddress.getIpAddress();
-        String translatedPort = String.valueOf(translatedSourceAddress.getPortNumber());
+        int translatedPort = translatedSourceAddress.getPortNumber();
         int idleTimeout=0;
-        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE) {
+        if(tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
             idleTimeout = NatConstants.DEFAULT_NAPT_IDLE_TIMEOUT;
         }
         long metaDataValue = routerId;
@@ -147,14 +278,18 @@ public class NaptEventHandler {
         }
         LOG.debug("NAT Service : Intranet VPN ID {}", intranetVpnId);
         LOG.debug("NAT Service : Router ID {}", routerId);
-        FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef, NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME,
-                idleTimeout, 0, NatUtil.getCookieNaptFlow(metaDataValue), buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
-                buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId, protocol));
+        FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef,
+                NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME, idleTimeout, 0,
+                NatUtil.getCookieNaptFlow(metaDataValue),
+                buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
+                buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId,
+                        protocol, extGwMacAddress));
 
         snatFlowEntity.setSendFlowRemFlag(true);
 
         LOG.debug("NAT Service : Installing the NAPT flow in the table {} for the switch with the DPN ID {} ", tableId, dpnId);
-        mdsalManager.installFlow(snatFlowEntity);
+        mdsalManager.syncInstallFlow(snatFlowEntity, 1);
+        LOG.trace("NAT Service : Exited buildAndInstallNatflows");
     }
 
     private static List<MatchInfo> buildAndGetMatchInfo(String ip, int port, short tableId, NAPTEntryEvent.Protocol protocol, long segmentId, long vpnId){
@@ -173,7 +308,7 @@ public class NaptEventHandler {
         }
 
         MatchInfo metaDataMatchInfo = null;
-        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+        if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
             ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_source, new String[] {ipAddressAsString, "32" });
             if(protocol == NAPTEntryEvent.Protocol.TCP) {
                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
@@ -182,9 +317,10 @@ public class NaptEventHandler {
                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
                 portMatchInfo = new MatchInfo(MatchFieldType.udp_src, new long[]{port});
             }
-            metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID});
+            metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata,
+                    new BigInteger[] { MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID });
         }else{
-            ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });         
+            ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });
             if(protocol == NAPTEntryEvent.Protocol.TCP) {
                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
                 portMatchInfo = new MatchInfo(MatchFieldType.tcp_dst, new long[]{port});
@@ -199,41 +335,58 @@ public class NaptEventHandler {
         matchInfo.add(ipMatchInfo);
         matchInfo.add(protocolMatchInfo);
         matchInfo.add(portMatchInfo);
-        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
+        if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
             matchInfo.add(metaDataMatchInfo);
         }
         return matchInfo;
     }
 
-    private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, String port, long segmentId, long vpnId, short tableId, NAPTEntryEvent.Protocol protocol) {
+    private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, int port, long segmentId, long vpnId,
+                                                                             short tableId, NAPTEntryEvent.Protocol protocol, String extGwMacAddress) {
         ActionInfo ipActionInfo = null;
+        ActionInfo macActionInfo = null;
         ActionInfo portActionInfo = null;
         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
+        switch (tableId) {
+            case NwConstants.OUTBOUND_NAPT_TABLE:
+                ipActionInfo = new ActionSetSourceIp(ipAddress);
+                // Added External Gateway MAC Address
+                macActionInfo = new ActionSetFieldEthernetSource(new MacAddress(extGwMacAddress));
+                if (protocol == NAPTEntryEvent.Protocol.TCP) {
+                    portActionInfo = new ActionSetTcpSourcePort(port);
+                } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
+                    portActionInfo = new ActionSetUdpSourcePort(port);
+                }
+                // reset the split-horizon bit to allow traffic from tunnel to be sent back to the provider port
+                instructionInfo.add(new InstructionInfo(InstructionType.write_metadata,
+                        new BigInteger[]{MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID.or(MetaDataUtil.METADATA_MASK_SH_FLAG)}));
+                break;
+
+            case NwConstants.INBOUND_NAPT_TABLE:
+                ipActionInfo = new ActionSetDestinationIp(ipAddress);
+                if (protocol == NAPTEntryEvent.Protocol.TCP) {
+                    portActionInfo = new ActionSetTcpDestinationPort(port);
+                } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
+                    portActionInfo = new ActionSetUdpDestinationPort(port);
+                }
+                instructionInfo.add(new InstructionInfo(InstructionType.write_metadata,
+                        new BigInteger[]{MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID}));
+                break;
 
-        if(tableId == NatConstants.OUTBOUND_NAPT_TABLE){
-            ipActionInfo = new ActionInfo(ActionType.set_source_ip, new String[] {ipAddress});
-            if(protocol == NAPTEntryEvent.Protocol.TCP) {
-               portActionInfo = new ActionInfo( ActionType.set_tcp_source_port, new String[] {port});
-            } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
-               portActionInfo = new ActionInfo( ActionType.set_udp_source_port, new String[] {port});
-            }
-            instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID}));
-        }else{
-            ipActionInfo = new ActionInfo(ActionType.set_destination_ip, new String[] {ipAddress});
-            if(protocol == NAPTEntryEvent.Protocol.TCP) {
-               portActionInfo = new ActionInfo( ActionType.set_tcp_destination_port, new String[] {port});
-            } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
-               portActionInfo = new ActionInfo( ActionType.set_udp_destination_port, new String[] {port});
-            }
-            instructionInfo.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[]{BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID}));
+            default:
+                LOG.error("NAT Service : Neither OUTBOUND_NAPT_TABLE nor INBOUND_NAPT_TABLE matches with input table id {}", tableId);
+                return null;
         }
 
         listActionInfo.add(ipActionInfo);
         listActionInfo.add(portActionInfo);
-
+        if (macActionInfo != null) {
+            listActionInfo.add(macActionInfo);
+            LOG.debug("NAT Service : External GW MAC Address {} is found  ", macActionInfo);
+        }
         instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
-        instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.NAPT_PFIB_TABLE }));
+        instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.NAPT_PFIB_TABLE}));
 
         return instructionInfo;
     }
@@ -247,9 +400,60 @@ public class NaptEventHandler {
         //Build the flow with the port IP and port as the match info.
         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(segmentId), ip, port);
         FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
-        LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NatConstants.INBOUND_NAPT_TABLE, dpnId);
+        LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId);
         mdsalManager.removeFlow(snatFlowEntity);
 
     }
 
+    protected byte[] buildNaptPacketOut(Ethernet etherPkt) {
+
+        LOG.debug("NAT Service : About to build Napt Packet Out");
+        if (etherPkt.getPayload() instanceof IPv4) {
+            byte[] rawPkt;
+            IPv4 ipPkt = (IPv4) etherPkt.getPayload();
+            if ((ipPkt.getPayload() instanceof TCP) || (ipPkt.getPayload() instanceof UDP) ) {
+                try {
+                    rawPkt = etherPkt.serialize();
+                    return rawPkt;
+                } catch (PacketException e2) {
+                    // TODO Auto-generated catch block
+                    e2.printStackTrace();
+                    return null;
+                }
+             } else {
+                 LOG.error("NAT Service : Unable to build NaptPacketOut since its neither TCP nor UDP");
+                 return null;
+             }
+        }
+        LOG.error("NAT Service : Unable to build NaptPacketOut since its not IPv4 packet");
+        return null;
+
+    }
+
+    private void sendNaptPacketOut(byte[] pktOut, InterfaceInfo infInfo, List<ActionInfo> actionInfos, Long routerId) {
+        LOG.trace("NAT Service: Sending packet out DpId {}, interfaceInfo {}", infInfo.getDpId(), infInfo);
+        // set inPort, and action as OFPP_TABLE so that it starts from table 0 (lowest table as per spec)
+        actionInfos.add(new ActionSetFieldTunnelId(2, BigInteger.valueOf(routerId)));
+        actionInfos.add(new ActionOutput(3, new Uri("0xfffffff9")));
+        NodeConnectorRef inPort = MDSALUtil.getNodeConnRef(infInfo.getDpId(), String.valueOf(infInfo.getPortNo()));
+        LOG.debug("NAT Service : inPort for packetout is being set to {}", String.valueOf(infInfo.getPortNo()));
+        TransmitPacketInput output = MDSALUtil.getPacketOut(actionInfos, pktOut, infInfo.getDpId().longValue(), inPort);
+        LOG.trace("NAT Service: Transmitting packet: {}",output);
+        this.pktService.transmitPacket(output);
+    }
+
+    private String getInterfaceNameFromTag(long portTag) {
+        String interfaceName = null;
+        GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex(new Integer((int)portTag)).build();
+        Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput = interfaceManagerRpc.getInterfaceFromIfIndex(input);
+        try {
+            GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult();
+            interfaceName = output.getInterfaceName();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("NAT Service : Error while retrieving the interfaceName from tag using getInterfaceFromIfIndex RPC");
+        }
+        LOG.trace("NAT Service : Returning interfaceName {} for tag {} form getInterfaceNameFromTag", interfaceName, portTag);
+        return interfaceName;
+    }
+
 }