242f4848209c8c4afa07978c2274032135c5847b
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NaptEventHandler.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import java.math.BigInteger;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.concurrent.ExecutionException;
17 import java.util.concurrent.Future;
18 import org.opendaylight.controller.liblldp.NetUtils;
19 import org.opendaylight.controller.liblldp.PacketException;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.genius.interfacemanager.globals.InterfaceInfo;
22 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
23 import org.opendaylight.genius.mdsalutil.ActionInfo;
24 import org.opendaylight.genius.mdsalutil.ActionType;
25 import org.opendaylight.genius.mdsalutil.FlowEntity;
26 import org.opendaylight.genius.mdsalutil.InstructionInfo;
27 import org.opendaylight.genius.mdsalutil.InstructionType;
28 import org.opendaylight.genius.mdsalutil.MDSALUtil;
29 import org.opendaylight.genius.mdsalutil.MatchFieldType;
30 import org.opendaylight.genius.mdsalutil.MatchInfo;
31 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
32 import org.opendaylight.genius.mdsalutil.NwConstants;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
35 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
36 import org.opendaylight.genius.mdsalutil.packet.IPv4;
37 import org.opendaylight.genius.mdsalutil.packet.TCP;
38 import org.opendaylight.genius.mdsalutil.packet.UDP;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
48 import org.opendaylight.yangtools.yang.common.RpcResult;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 public class NaptEventHandler {
53     private static final Logger LOG = LoggerFactory.getLogger(NaptEventHandler.class);
54     private final DataBroker dataBroker;
55     private static IMdsalApiManager mdsalManager;
56     private final PacketProcessingService pktService;
57     private final OdlInterfaceRpcService interfaceManagerRpc;
58     private final NaptManager naptManager;
59     private IInterfaceManager interfaceManager;
60
61     public NaptEventHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
62                             final NaptManager naptManager,
63                             final PacketProcessingService pktService,
64                             final OdlInterfaceRpcService interfaceManagerRpc,
65                             final IInterfaceManager interfaceManager) {
66         this.dataBroker = dataBroker;
67         NaptEventHandler.mdsalManager = mdsalManager;
68         this.naptManager = naptManager;
69         this.pktService = pktService;
70         this.interfaceManagerRpc = interfaceManagerRpc;
71         this.interfaceManager = interfaceManager;
72     }
73
74     public void handleEvent(NAPTEntryEvent naptEntryEvent){
75     /*
76             Flow programming logic of the OUTBOUND NAPT TABLE :
77             1) Get the internal IP address, port number, router ID from the event.
78             2) Use the NAPT service getExternalAddressMapping() to get the External IP and the port.
79             3) Build the flow for replacing the Internal IP and port with the External IP and port.
80               a) Write the matching criteria.
81               b) Match the router ID in the metadata.
82               d) Write the VPN ID to the metadata.
83               e) Write the other data.
84               f) Set the apply actions instruction with the action setfield.
85             4) Write the flow to the OUTBOUND NAPT Table and forward to FIB table for routing the traffic.
86
87             Flow programming logic of the INBOUND NAPT TABLE :
88             Same as Outbound table logic except that :
89             1) Build the flow for replacing the External IP and port with the Internal IP and port.
90             2) Match the VPN ID in the metadata.
91             3) Write the router ID to the metadata.
92             5) Write the flow to the INBOUND NAPT Table and forward to FIB table for routing the traffic.
93     */
94         try {
95         Long routerId = naptEntryEvent.getRouterId();
96         LOG.info("NAT Service : handleEvent() entry for IP {}, port {}, routerID {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
97
98         //Get the DPN ID
99         BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
100         long bgpVpnId = NatConstants.INVALID_ID;
101         if(dpnId == null ){
102             LOG.warn("NAT Service : dpnId is null. Assuming the router ID {} as the BGP VPN ID and proceeding....", routerId);
103             bgpVpnId = routerId;
104             LOG.debug("NAT Service : BGP VPN ID {}", bgpVpnId);
105             String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
106             String routerName = NatUtil.getRouterIdfromVpnInstance(dataBroker, vpnName);
107             if (routerName == null) {
108                 LOG.error("NAT Service: Unable to find router for VpnName {}", vpnName);
109                 return;
110             }
111             routerId = NatUtil.getVpnId(dataBroker, routerName);
112             LOG.debug("NAT Service : Router ID {}", routerId);
113             dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
114             if(dpnId == null){
115                 LOG.error("NAT Service : dpnId is null for the router {}", routerId);
116                 return;
117             }
118         }
119         if(naptEntryEvent.getOperation() == NAPTEntryEvent.Operation.ADD) {
120             LOG.debug("NAT Service : Inside Add operation of NaptEventHandler");
121
122             //Get the external network ID from the ExternalRouter model
123             Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
124             if(networkId == null ){
125                 LOG.error("NAT Service : networkId is null");
126                 return;
127             }
128
129             //Get the VPN ID from the ExternalNetworks model
130             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
131             if(vpnUuid == null ){
132                 LOG.error("NAT Service : vpnUuid is null");
133                 return;
134             }
135             Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
136
137             //Get the internal IpAddress, internal port number from the event
138             String internalIpAddress = naptEntryEvent.getIpAddress();
139             int internalPort = naptEntryEvent.getPortNumber();
140             SessionAddress internalAddress = new SessionAddress(internalIpAddress, internalPort);
141             NAPTEntryEvent.Protocol protocol = naptEntryEvent.getProtocol();
142
143             //Get the external IP address for the corresponding internal IP address
144             SessionAddress externalAddress = naptManager.getExternalAddressMapping(routerId, internalAddress, naptEntryEvent.getProtocol());
145             if(externalAddress == null ){
146                 if(externalAddress == null){
147                     LOG.error("NAT Service : externalAddress is null");
148                     return;
149                 }
150             }
151             //Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
152             if(!naptEntryEvent.isPktProcessed()) {
153                 buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, internalAddress, externalAddress, protocol);
154                 buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId, externalAddress, internalAddress, protocol);
155             }
156
157             //Send Packetout - tcp or udp packets which got punted to controller.
158             BigInteger metadata = naptEntryEvent.getPacketReceived().getMatch().getMetadata().getMetadata();
159             byte[] inPayload = naptEntryEvent.getPacketReceived().getPayload();
160             Ethernet ethPkt = new Ethernet();
161             if (inPayload != null) {
162                 try {
163                     ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
164                 } catch (Exception e) {
165                     LOG.warn("Failed to decode Packet", e);
166                     return;
167                 }
168             }
169
170
171             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
172             LOG.debug("NAT Service : portTag from incoming packet is {}", portTag);
173             String interfaceName = getInterfaceNameFromTag(portTag);
174             LOG.debug("NAT Service : interfaceName fetched from portTag is {}", interfaceName);
175             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = null;
176             long vlanId =0;
177             iface = interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
178             if(iface == null) {
179                 LOG.error("NAT Service : Unable to read interface {} from config DataStore", interfaceName);
180                 return;
181             }
182             IfL2vlan ifL2vlan = iface.getAugmentation(IfL2vlan.class);
183             if(ifL2vlan != null && ifL2vlan.getVlanId() !=null){
184                 vlanId = ifL2vlan.getVlanId().getValue() == null ? 0 : ifL2vlan.getVlanId().getValue();
185             }
186             InterfaceInfo infInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
187             if(infInfo !=null) {
188                 LOG.debug("NAT Service : portName fetched from interfaceManager is {}", infInfo.getPortName());
189             }
190
191             byte[] pktOut = buildNaptPacketOut(ethPkt);
192
193             List<ActionInfo> actionInfos  = new ArrayList<ActionInfo>();
194             if (ethPkt.getPayload() instanceof IPv4) {
195                 IPv4 ipPkt = (IPv4) ethPkt.getPayload();
196                 if ((ipPkt.getPayload() instanceof TCP) || (ipPkt.getPayload() instanceof UDP) ) {
197                     if (ethPkt.getEtherType() != (short)NwConstants.ETHTYPE_802_1Q) {
198                         // VLAN Access port
199                         if(infInfo != null) {
200                             LOG.debug("NAT Service : vlanId is {}", vlanId);
201                             if(vlanId != 0) {
202                                 // Push vlan
203                                 actionInfos.add(new ActionInfo(ActionType.push_vlan, new String[] {}, 0));
204                                 actionInfos.add(new ActionInfo(ActionType.set_field_vlan_vid,
205                                            new String[] { Long.toString(vlanId) }, 1));
206                             } else {
207                                 LOG.debug("NAT Service : No vlanId {}, may be untagged", vlanId);
208                             }
209                         } else {
210                             LOG.error("NAT Service : error in getting interfaceInfo");
211                             return;
212                         }
213                     } else {
214                         // VLAN Trunk Port
215                         LOG.debug("NAT Service : This is VLAN Trunk port case - need not do VLAN tagging again");
216                     }
217                 }
218             }
219             if(pktOut != null) {
220                 sendNaptPacketOut(pktOut, infInfo, actionInfos, routerId);
221             } else {
222                 LOG.warn("NAT Service : Unable to send Packet Out");
223             }
224
225         }else{
226             LOG.debug("NAT Service : Inside delete Operation of NaptEventHandler");
227             removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber());
228         }
229
230         LOG.info("NAT Service : handleNaptEvent() exited for IP, port, routerID : {}", naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
231         } catch (Exception e){
232             LOG.error("NAT Service :Exception in NaptEventHandler.handleEvent() payload {}", naptEntryEvent,e);
233         }
234     }
235
236     public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId, long bgpVpnId, SessionAddress actualSourceAddress,
237                                          SessionAddress translatedSourceAddress, NAPTEntryEvent.Protocol protocol){
238         LOG.debug("NAT Service : Build and install NAPT flows in InBound and OutBound tables for dpnId {} and routerId {}", dpnId, routerId);
239         //Build the flow for replacing the actual IP and port with the translated IP and port.
240         String actualIp = actualSourceAddress.getIpAddress();
241         int actualPort = actualSourceAddress.getPortNumber();
242         String translatedIp = translatedSourceAddress.getIpAddress();
243         String translatedPort = String.valueOf(translatedSourceAddress.getPortNumber());
244         int idleTimeout=0;
245         if(tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
246             idleTimeout = NatConstants.DEFAULT_NAPT_IDLE_TIMEOUT;
247         }
248         long metaDataValue = routerId;
249         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(metaDataValue), actualIp, actualPort);
250
251         long intranetVpnId;
252         if(bgpVpnId != NatConstants.INVALID_ID){
253             intranetVpnId = bgpVpnId;
254         }else{
255             intranetVpnId = routerId;
256         }
257         LOG.debug("NAT Service : Intranet VPN ID {}", intranetVpnId);
258         LOG.debug("NAT Service : Router ID {}", routerId);
259         FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef, NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME,
260                 idleTimeout, 0, NatUtil.getCookieNaptFlow(metaDataValue), buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
261                 buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId, protocol));
262
263         snatFlowEntity.setSendFlowRemFlag(true);
264
265         LOG.debug("NAT Service : Installing the NAPT flow in the table {} for the switch with the DPN ID {} ", tableId, dpnId);
266         mdsalManager.syncInstallFlow(snatFlowEntity, 1);
267         LOG.trace("NAT Service : Exited buildAndInstallNatflows");
268     }
269
270     private static List<MatchInfo> buildAndGetMatchInfo(String ip, int port, short tableId, NAPTEntryEvent.Protocol protocol, long segmentId, long vpnId){
271         MatchInfo ipMatchInfo = null;
272         MatchInfo portMatchInfo = null;
273         MatchInfo protocolMatchInfo = null;
274         InetAddress ipAddress = null;
275         String ipAddressAsString = null;
276         try {
277             ipAddress = InetAddress.getByName(ip);
278             ipAddressAsString = ipAddress.getHostAddress();
279
280         } catch (UnknownHostException e) {
281             LOG.error("NAT Service : UnknowHostException in buildAndGetMatchInfo. Failed  to build NAPT Flow for  ip {}", ipAddress);
282             return null;
283         }
284
285         MatchInfo metaDataMatchInfo = null;
286         if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
287             ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_source, new String[] {ipAddressAsString, "32" });
288             if(protocol == NAPTEntryEvent.Protocol.TCP) {
289                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
290                 portMatchInfo = new MatchInfo(MatchFieldType.tcp_src, new long[]{port});
291             } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
292                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
293                 portMatchInfo = new MatchInfo(MatchFieldType.udp_src, new long[]{port});
294             }
295             metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata,
296                     new BigInteger[] { MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID });
297         }else{
298             ipMatchInfo = new MatchInfo(MatchFieldType.ipv4_destination, new String[] {ipAddressAsString, "32" });
299             if(protocol == NAPTEntryEvent.Protocol.TCP) {
300                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.TCP.intValue()});
301                 portMatchInfo = new MatchInfo(MatchFieldType.tcp_dst, new long[]{port});
302             } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
303                 protocolMatchInfo = new MatchInfo(MatchFieldType.ip_proto, new long[] {IPProtocols.UDP.intValue()});
304                 portMatchInfo = new MatchInfo(MatchFieldType.udp_dst, new long[]{port});
305             }
306             //metaDataMatchInfo = new MatchInfo(MatchFieldType.metadata, new BigInteger[]{BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID});
307         }
308         ArrayList<MatchInfo> matchInfo = new ArrayList<>();
309         matchInfo.add(new MatchInfo(MatchFieldType.eth_type, new long[] { 0x0800L }));
310         matchInfo.add(ipMatchInfo);
311         matchInfo.add(protocolMatchInfo);
312         matchInfo.add(portMatchInfo);
313         if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
314             matchInfo.add(metaDataMatchInfo);
315         }
316         return matchInfo;
317     }
318
319     private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, String port, long segmentId, long vpnId, short tableId, NAPTEntryEvent.Protocol protocol) {
320         ActionInfo ipActionInfo = null;
321         ActionInfo portActionInfo = null;
322         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
323         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
324
325         if(tableId == NwConstants.OUTBOUND_NAPT_TABLE){
326             ipActionInfo = new ActionInfo(ActionType.set_source_ip, new String[] {ipAddress});
327             if(protocol == NAPTEntryEvent.Protocol.TCP) {
328                portActionInfo = new ActionInfo( ActionType.set_tcp_source_port, new String[] {port});
329             } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
330                portActionInfo = new ActionInfo( ActionType.set_udp_source_port, new String[] {port});
331             }
332             // reset the split-horizon bit to allow traffic from tunnel to be
333             // sent back to the provider port
334             instructionInfo.add(new InstructionInfo(InstructionType.write_metadata,
335                     new BigInteger[] { MetaDataUtil.getVpnIdMetadata(vpnId),
336                             MetaDataUtil.METADATA_MASK_VRFID.or(MetaDataUtil.METADATA_MASK_SH_FLAG) }));
337         }else{
338             ipActionInfo = new ActionInfo(ActionType.set_destination_ip, new String[] {ipAddress});
339             if(protocol == NAPTEntryEvent.Protocol.TCP) {
340                portActionInfo = new ActionInfo( ActionType.set_tcp_destination_port, new String[] {port});
341             } else if(protocol == NAPTEntryEvent.Protocol.UDP) {
342                portActionInfo = new ActionInfo( ActionType.set_udp_destination_port, new String[] {port});
343             }
344             instructionInfo.add(new InstructionInfo(InstructionType.write_metadata,
345                     new BigInteger[] { MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
346         }
347
348         listActionInfo.add(ipActionInfo);
349         listActionInfo.add(portActionInfo);
350
351         instructionInfo.add(new InstructionInfo(InstructionType.apply_actions, listActionInfo));
352         instructionInfo.add(new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.NAPT_PFIB_TABLE
353         }));
354
355         return instructionInfo;
356     }
357
358     void removeNatFlows(BigInteger dpnId, short tableId ,long segmentId, String ip, int port){
359         if(dpnId == null || dpnId.equals(BigInteger.ZERO)){
360             LOG.error("NAT Service : DPN ID {} is invalid" , dpnId);
361         }
362         LOG.debug("NAT Service : Remove NAPT flows for dpnId {}, segmentId {}, ip {} and port {} ", dpnId, segmentId, ip, port);
363
364         //Build the flow with the port IP and port as the match info.
365         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(segmentId), ip, port);
366         FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
367         LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId);
368         mdsalManager.removeFlow(snatFlowEntity);
369
370     }
371
372     protected byte[] buildNaptPacketOut(Ethernet etherPkt) {
373
374         LOG.debug("NAT Service : About to build Napt Packet Out");
375         if (etherPkt.getPayload() instanceof IPv4) {
376             byte[] rawPkt;
377             IPv4 ipPkt = (IPv4) etherPkt.getPayload();
378             if ((ipPkt.getPayload() instanceof TCP) || (ipPkt.getPayload() instanceof UDP) ) {
379                 try {
380                     rawPkt = etherPkt.serialize();
381                     return rawPkt;
382                 } catch (PacketException e2) {
383                     // TODO Auto-generated catch block
384                     e2.printStackTrace();
385                     return null;
386                 }
387              } else {
388                  LOG.error("NAT Service : Unable to build NaptPacketOut since its neither TCP nor UDP");
389                  return null;
390              }
391         }
392         LOG.error("NAT Service : Unable to build NaptPacketOut since its not IPv4 packet");
393         return null;
394
395     }
396
397     private void sendNaptPacketOut(byte[] pktOut, InterfaceInfo infInfo, List<ActionInfo> actionInfos, Long routerId) {
398         LOG.trace("NAT Service: Sending packet out DpId {}, interfaceInfo {}", infInfo.getDpId(), infInfo);
399         // set in_port, and action as OFPP_TABLE so that it starts from table 0 (lowest table as per spec)
400         actionInfos.add(new ActionInfo(ActionType.set_field_tunnel_id, new BigInteger[] {
401                   BigInteger.valueOf(routerId)}, 2));
402         actionInfos.add(new ActionInfo(ActionType.output, new String[] { "0xfffffff9" }, 3));
403         NodeConnectorRef in_port = MDSALUtil.getNodeConnRef(infInfo.getDpId(), String.valueOf(infInfo.getPortNo()));
404         LOG.debug("NAT Service : in_port for packetout is being set to {}", String.valueOf(infInfo.getPortNo()));
405         TransmitPacketInput output = MDSALUtil.getPacketOut(actionInfos, pktOut, infInfo.getDpId().longValue(), in_port);
406         LOG.trace("NAT Service: Transmitting packet: {}",output);
407         this.pktService.transmitPacket(output);
408     }
409
410     private String getInterfaceNameFromTag(long portTag) {
411         String interfaceName = null;
412         GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex(new Integer((int)portTag)).build();
413         Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput = interfaceManagerRpc.getInterfaceFromIfIndex(input);
414         try {
415             GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult();
416             interfaceName = output.getInterfaceName();
417         } catch (InterruptedException | ExecutionException e) {
418             LOG.error("NAT Service : Error while retrieving the interfaceName from tag using getInterfaceFromIfIndex RPC");
419         }
420         LOG.trace("NAT Service : Returning interfaceName {} for tag {} form getInterfaceNameFromTag", interfaceName, portTag);
421         return interfaceName;
422     }
423
424 }