Use Java declarations instead of Google Collections
[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.FlowEntity;
25 import org.opendaylight.genius.mdsalutil.InstructionInfo;
26 import org.opendaylight.genius.mdsalutil.MDSALUtil;
27 import org.opendaylight.genius.mdsalutil.MatchInfo;
28 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.actions.ActionOutput;
31 import org.opendaylight.genius.mdsalutil.actions.ActionPushVlan;
32 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
33 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
34 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
35 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldVlanVid;
36 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
37 import org.opendaylight.genius.mdsalutil.actions.ActionSetTcpDestinationPort;
38 import org.opendaylight.genius.mdsalutil.actions.ActionSetTcpSourcePort;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetUdpDestinationPort;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetUdpSourcePort;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
46 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
47 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
49 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
50 import org.opendaylight.genius.mdsalutil.matches.MatchTcpDestinationPort;
51 import org.opendaylight.genius.mdsalutil.matches.MatchTcpSourcePort;
52 import org.opendaylight.genius.mdsalutil.matches.MatchUdpDestinationPort;
53 import org.opendaylight.genius.mdsalutil.matches.MatchUdpSourcePort;
54 import org.opendaylight.genius.mdsalutil.packet.Ethernet;
55 import org.opendaylight.genius.mdsalutil.packet.IPv4;
56 import org.opendaylight.genius.mdsalutil.packet.TCP;
57 import org.opendaylight.genius.mdsalutil.packet.UDP;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetInterfaceFromIfIndexOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
69 import org.opendaylight.yangtools.yang.common.RpcResult;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 public class NaptEventHandler {
74     private static final Logger LOG = LoggerFactory.getLogger(NaptEventHandler.class);
75     private final DataBroker dataBroker;
76     private static IMdsalApiManager mdsalManager;
77     private final PacketProcessingService pktService;
78     private final OdlInterfaceRpcService interfaceManagerRpc;
79     private final NaptManager naptManager;
80     private IInterfaceManager interfaceManager;
81
82     public NaptEventHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
83                             final NaptManager naptManager,
84                             final PacketProcessingService pktService,
85                             final OdlInterfaceRpcService interfaceManagerRpc,
86                             final IInterfaceManager interfaceManager) {
87         this.dataBroker = dataBroker;
88         NaptEventHandler.mdsalManager = mdsalManager;
89         this.naptManager = naptManager;
90         this.pktService = pktService;
91         this.interfaceManagerRpc = interfaceManagerRpc;
92         this.interfaceManager = interfaceManager;
93     }
94
95     // TODO Clean up the exception handling
96     @SuppressWarnings("checkstyle:IllegalCatch")
97     public void handleEvent(NAPTEntryEvent naptEntryEvent) {
98     /*
99             Flow programming logic of the OUTBOUND NAPT TABLE :
100             1) Get the internal IP address, port number, router ID from the event.
101             2) Use the NAPT service getExternalAddressMapping() to get the External IP and the port.
102             3) Build the flow for replacing the Internal IP and port with the External IP and port.
103               a) Write the matching criteria.
104               b) Match the router ID in the metadata.
105               d) Write the VPN ID to the metadata.
106               e) Write the other data.
107               f) Set the apply actions instruction with the action setfield.
108             4) Write the flow to the OUTBOUND NAPT Table and forward to FIB table for routing the traffic.
109
110             Flow programming logic of the INBOUND NAPT TABLE :
111             Same as Outbound table logic except that :
112             1) Build the flow for replacing the External IP and port with the Internal IP and port.
113             2) Match the VPN ID in the metadata.
114             3) Write the router ID to the metadata.
115             5) Write the flow to the INBOUND NAPT Table and forward to FIB table for routing the traffic.
116     */
117         try {
118             Long routerId = naptEntryEvent.getRouterId();
119             LOG.info("NAT Service : handleEvent() entry for IP {}, port {}, routerID {}",
120                 naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
121             // Get the External Gateway MAC Address
122             String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
123             if (extGwMacAddress != null) {
124                 LOG.debug("NAT Service : External Gateway MAC address {} found for External Router ID {}",
125                     extGwMacAddress, routerId);
126             } else {
127                 LOG.error("NAT Service : No External Gateway MAC address found for External Router ID {}", routerId);
128                 return;
129             }
130             //Get the DPN ID
131             BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
132             long bgpVpnId = NatConstants.INVALID_ID;
133             if (dpnId == null) {
134                 LOG.warn("NAT Service : dpnId is null. Assuming the router ID {} as the BGP VPN ID and proceeding....",
135                     routerId);
136                 bgpVpnId = routerId;
137                 LOG.debug("NAT Service : BGP VPN ID {}", bgpVpnId);
138                 String vpnName = NatUtil.getRouterName(dataBroker, bgpVpnId);
139                 String routerName = NatUtil.getRouterIdfromVpnInstance(dataBroker, vpnName);
140                 if (routerName == null) {
141                     LOG.error("NAT Service: Unable to find router for VpnName {}", vpnName);
142                     return;
143                 }
144                 routerId = NatUtil.getVpnId(dataBroker, routerName);
145                 LOG.debug("NAT Service : Router ID {}", routerId);
146                 dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
147                 if (dpnId == null) {
148                     LOG.error("NAT Service : dpnId is null for the router {}", routerId);
149                     return;
150                 }
151             }
152             if (naptEntryEvent.getOperation() == NAPTEntryEvent.Operation.ADD) {
153                 LOG.debug("NAT Service : Inside Add operation of NaptEventHandler");
154
155                 //Get the external network ID from the ExternalRouter model
156                 Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
157                 if (networkId == null) {
158                     LOG.error("NAT Service : networkId is null");
159                     return;
160                 }
161
162                 //Get the VPN ID from the ExternalNetworks model
163                 Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
164                 if (vpnUuid == null) {
165                     LOG.error("NAT Service : vpnUuid is null");
166                     return;
167                 }
168                 Long vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
169
170                 //Get the internal IpAddress, internal port number from the event
171                 String internalIpAddress = naptEntryEvent.getIpAddress();
172                 int internalPort = naptEntryEvent.getPortNumber();
173                 SessionAddress internalAddress = new SessionAddress(internalIpAddress, internalPort);
174                 NAPTEntryEvent.Protocol protocol = naptEntryEvent.getProtocol();
175
176                 //Get the external IP address for the corresponding internal IP address
177                 SessionAddress externalAddress =
178                     naptManager.getExternalAddressMapping(routerId, internalAddress, naptEntryEvent.getProtocol());
179                 if (externalAddress == null) {
180                     LOG.error("NAT Service : externalAddress is null");
181                     return;
182                 }
183                 // Build and install the NAPT translation flows in the Outbound and Inbound NAPT tables
184                 if (!naptEntryEvent.isPktProcessed()) {
185                     // Added External Gateway MAC Address
186                     buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId,
187                         internalAddress, externalAddress, protocol, extGwMacAddress);
188                     buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnId, routerId, bgpVpnId,
189                         externalAddress, internalAddress, protocol, extGwMacAddress);
190                 }
191
192                 //Send Packetout - tcp or udp packets which got punted to controller.
193                 BigInteger metadata = naptEntryEvent.getPacketReceived().getMatch().getMetadata().getMetadata();
194                 byte[] inPayload = naptEntryEvent.getPacketReceived().getPayload();
195                 Ethernet ethPkt = new Ethernet();
196                 if (inPayload != null) {
197                     try {
198                         ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
199                     } catch (Exception e) {
200                         LOG.warn("NAT Service : Failed to decode Packet", e);
201                         return;
202                     }
203                 }
204
205
206                 long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
207                 LOG.debug("NAT Service : portTag from incoming packet is {}", portTag);
208                 String interfaceName = getInterfaceNameFromTag(portTag);
209                 LOG.debug("NAT Service : interfaceName fetched from portTag is {}", interfaceName);
210                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
211                     .interfaces.Interface iface = null;
212                 int vlanId = 0;
213                 iface = interfaceManager.getInterfaceInfoFromConfigDataStore(interfaceName);
214                 if (iface == null) {
215                     LOG.error("NAT Service : Unable to read interface {} from config DataStore", interfaceName);
216                     return;
217                 }
218                 IfL2vlan ifL2vlan = iface.getAugmentation(IfL2vlan.class);
219                 if (ifL2vlan != null && ifL2vlan.getVlanId() != null) {
220                     vlanId = ifL2vlan.getVlanId().getValue() == null ? 0 : ifL2vlan.getVlanId().getValue();
221                 }
222                 InterfaceInfo infInfo = interfaceManager.getInterfaceInfoFromOperationalDataStore(interfaceName);
223                 if (infInfo != null) {
224                     LOG.debug("NAT Service : portName fetched from interfaceManager is {}", infInfo.getPortName());
225                 }
226
227                 byte[] pktOut = buildNaptPacketOut(ethPkt);
228
229                 List<ActionInfo> actionInfos = new ArrayList<ActionInfo>();
230                 if (ethPkt.getPayload() instanceof IPv4) {
231                     IPv4 ipPkt = (IPv4) ethPkt.getPayload();
232                     if ((ipPkt.getPayload() instanceof TCP) || (ipPkt.getPayload() instanceof UDP)) {
233                         if (ethPkt.getEtherType() != (short) NwConstants.ETHTYPE_802_1Q) {
234                             // VLAN Access port
235                             if (infInfo != null) {
236                                 LOG.debug("NAT Service : vlanId is {}", vlanId);
237                                 if (vlanId != 0) {
238                                     // Push vlan
239                                     actionInfos.add(new ActionPushVlan(0));
240                                     actionInfos.add(new ActionSetFieldVlanVid(1, vlanId));
241                                 } else {
242                                     LOG.debug("NAT Service : No vlanId {}, may be untagged", vlanId);
243                                 }
244                             } else {
245                                 LOG.error("NAT Service : error in getting interfaceInfo");
246                                 return;
247                             }
248                         } else {
249                             // VLAN Trunk Port
250                             LOG.debug("NAT Service : This is VLAN Trunk port case - need not do VLAN tagging again");
251                         }
252                     }
253                 }
254                 if (pktOut != null) {
255                     sendNaptPacketOut(pktOut, infInfo, actionInfos, routerId);
256                 } else {
257                     LOG.warn("NAT Service : Unable to send Packet Out");
258                 }
259
260             } else {
261                 LOG.debug("NAT Service : Inside delete Operation of NaptEventHandler");
262                 removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, routerId, naptEntryEvent.getIpAddress(),
263                     naptEntryEvent.getPortNumber());
264             }
265
266             LOG.info("NAT Service : handleNaptEvent() exited for IP {}, port {}, routerID : {}",
267                 naptEntryEvent.getIpAddress(), naptEntryEvent.getPortNumber(), routerId);
268         } catch (Exception e) {
269             LOG.error("NAT Service :Exception in NaptEventHandler.handleEvent() payload {}", naptEntryEvent, e);
270         }
271     }
272
273     public static void buildAndInstallNatFlows(BigInteger dpnId, short tableId, long vpnId, long routerId,
274                                                long bgpVpnId, SessionAddress actualSourceAddress,
275                                                SessionAddress translatedSourceAddress,
276                                                NAPTEntryEvent.Protocol protocol, String extGwMacAddress) {
277         LOG.debug("NAT Service : Build and install NAPT flows in InBound and OutBound tables for "
278             + "dpnId {} and routerId {}", dpnId, routerId);
279         //Build the flow for replacing the actual IP and port with the translated IP and port.
280         int idleTimeout = 0;
281         if (tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
282             idleTimeout = NatConstants.DEFAULT_NAPT_IDLE_TIMEOUT;
283         }
284         long intranetVpnId;
285         if (bgpVpnId != NatConstants.INVALID_ID) {
286             intranetVpnId = bgpVpnId;
287         } else {
288             intranetVpnId = routerId;
289         }
290         LOG.debug("NAT Service : Intranet VPN ID {}", intranetVpnId);
291         LOG.debug("NAT Service : Router ID {}", routerId);
292         String translatedIp = translatedSourceAddress.getIpAddress();
293         int translatedPort = translatedSourceAddress.getPortNumber();
294         String actualIp = actualSourceAddress.getIpAddress();
295         int actualPort = actualSourceAddress.getPortNumber();
296         String switchFlowRef =
297             NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), actualIp, actualPort);
298         FlowEntity snatFlowEntity = MDSALUtil.buildFlowEntity(dpnId, tableId, switchFlowRef,
299                 NatConstants.DEFAULT_NAPT_FLOW_PRIORITY, NatConstants.NAPT_FLOW_NAME, idleTimeout, 0,
300                 NatUtil.getCookieNaptFlow(routerId),
301                 buildAndGetMatchInfo(actualIp, actualPort, tableId, protocol, intranetVpnId, vpnId),
302                 buildAndGetSetActionInstructionInfo(translatedIp, translatedPort, intranetVpnId, vpnId, tableId,
303                         protocol, extGwMacAddress));
304
305         snatFlowEntity.setSendFlowRemFlag(true);
306
307         LOG.debug("NAT Service : Installing the NAPT flow in the table {} for the switch with the DPN ID {} ",
308             tableId, dpnId);
309         mdsalManager.syncInstallFlow(snatFlowEntity, 1);
310         LOG.trace("NAT Service : Exited buildAndInstallNatflows");
311     }
312
313     private static List<MatchInfo> buildAndGetMatchInfo(String ip, int port, short tableId,
314                                                         NAPTEntryEvent.Protocol protocol, long segmentId, long vpnId) {
315         MatchInfo ipMatchInfo = null;
316         MatchInfo portMatchInfo = null;
317         MatchInfo protocolMatchInfo = null;
318         InetAddress ipAddress = null;
319         String ipAddressAsString = null;
320         try {
321             ipAddress = InetAddress.getByName(ip);
322             ipAddressAsString = ipAddress.getHostAddress();
323
324         } catch (UnknownHostException e) {
325             LOG.error("NAT Service : UnknowHostException in buildAndGetMatchInfo. Failed  to build NAPT Flow for "
326                 + "ip {}", ipAddress);
327             return null;
328         }
329
330         MatchInfo metaDataMatchInfo = null;
331         if (tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
332             ipMatchInfo = new MatchIpv4Source(ipAddressAsString, "32");
333             if (protocol == NAPTEntryEvent.Protocol.TCP) {
334                 protocolMatchInfo = MatchIpProtocol.TCP;
335                 portMatchInfo = new MatchTcpSourcePort(port);
336             } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
337                 protocolMatchInfo = MatchIpProtocol.UDP;
338                 portMatchInfo = new MatchUdpSourcePort(port);
339             }
340             metaDataMatchInfo =
341                     new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID);
342         } else {
343             ipMatchInfo = new MatchIpv4Destination(ipAddressAsString, "32");
344             if (protocol == NAPTEntryEvent.Protocol.TCP) {
345                 protocolMatchInfo = MatchIpProtocol.TCP;
346                 portMatchInfo = new MatchTcpDestinationPort(port);
347             } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
348                 protocolMatchInfo = MatchIpProtocol.UDP;
349                 portMatchInfo = new MatchUdpDestinationPort(port);
350             }
351             //metaDataMatchInfo = new MatchMetadata(BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID);
352         }
353         ArrayList<MatchInfo> matchInfo = new ArrayList<>();
354         matchInfo.add(MatchEthernetType.IPV4);
355         matchInfo.add(ipMatchInfo);
356         matchInfo.add(protocolMatchInfo);
357         matchInfo.add(portMatchInfo);
358         if (tableId == NwConstants.OUTBOUND_NAPT_TABLE) {
359             matchInfo.add(metaDataMatchInfo);
360         }
361         return matchInfo;
362     }
363
364     private static List<InstructionInfo> buildAndGetSetActionInstructionInfo(String ipAddress, int port,
365                                                                              long segmentId, long vpnId,
366                                                                              short tableId,
367                                                                              NAPTEntryEvent.Protocol protocol,
368                                                                              String extGwMacAddress) {
369         ActionInfo ipActionInfo = null;
370         ActionInfo macActionInfo = null;
371         ActionInfo portActionInfo = null;
372         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
373         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
374         switch (tableId) {
375             case NwConstants.OUTBOUND_NAPT_TABLE:
376                 ipActionInfo = new ActionSetSourceIp(ipAddress);
377                 // Added External Gateway MAC Address
378                 macActionInfo = new ActionSetFieldEthernetSource(new MacAddress(extGwMacAddress));
379                 if (protocol == NAPTEntryEvent.Protocol.TCP) {
380                     portActionInfo = new ActionSetTcpSourcePort(port);
381                 } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
382                     portActionInfo = new ActionSetUdpSourcePort(port);
383                 }
384                 // reset the split-horizon bit to allow traffic from tunnel to be sent back to the provider port
385                 instructionInfo.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId),
386                     MetaDataUtil.METADATA_MASK_VRFID.or(MetaDataUtil.METADATA_MASK_SH_FLAG)));
387                 break;
388
389             case NwConstants.INBOUND_NAPT_TABLE:
390                 ipActionInfo = new ActionSetDestinationIp(ipAddress);
391                 if (protocol == NAPTEntryEvent.Protocol.TCP) {
392                     portActionInfo = new ActionSetTcpDestinationPort(port);
393                 } else if (protocol == NAPTEntryEvent.Protocol.UDP) {
394                     portActionInfo = new ActionSetUdpDestinationPort(port);
395                 }
396                 instructionInfo.add(new InstructionWriteMetadata(
397                         MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
398                 break;
399
400             default:
401                 LOG.error("NAT Service : Neither OUTBOUND_NAPT_TABLE nor INBOUND_NAPT_TABLE matches with "
402                     + "input table id {}", tableId);
403                 return null;
404         }
405
406         listActionInfo.add(ipActionInfo);
407         listActionInfo.add(portActionInfo);
408         if (macActionInfo != null) {
409             listActionInfo.add(macActionInfo);
410             LOG.debug("NAT Service : External GW MAC Address {} is found  ", macActionInfo);
411         }
412         instructionInfo.add(new InstructionApplyActions(listActionInfo));
413         instructionInfo.add(new InstructionGotoTable(NwConstants.NAPT_PFIB_TABLE));
414
415         return instructionInfo;
416     }
417
418     void removeNatFlows(BigInteger dpnId, short tableId ,long segmentId, String ip, int port) {
419         if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
420             LOG.error("NAT Service : DPN ID {} is invalid" , dpnId);
421         }
422         LOG.debug("NAT Service : Remove NAPT flows for dpnId {}, segmentId {}, ip {} and port {} ",
423             dpnId, segmentId, ip, port);
424
425         //Build the flow with the port IP and port as the match info.
426         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(segmentId), ip, port);
427         FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
428         LOG.debug("NAT Service : Remove the flow in the table {} for the switch with the DPN ID {}",
429             NwConstants.INBOUND_NAPT_TABLE, dpnId);
430         mdsalManager.removeFlow(snatFlowEntity);
431
432     }
433
434     protected byte[] buildNaptPacketOut(Ethernet etherPkt) {
435         LOG.debug("NAT Service : About to build Napt Packet Out");
436         if (etherPkt.getPayload() instanceof IPv4) {
437             byte[] rawPkt;
438             IPv4 ipPkt = (IPv4) etherPkt.getPayload();
439             if ((ipPkt.getPayload() instanceof TCP) || (ipPkt.getPayload() instanceof UDP)) {
440                 try {
441                     rawPkt = etherPkt.serialize();
442                     return rawPkt;
443                 } catch (PacketException e2) {
444                     LOG.error("failed to build NAPT Packet out ", e2);
445                     return null;
446                 }
447             } else {
448                 LOG.error("NAT Service : Unable to build NaptPacketOut since its neither TCP nor UDP");
449                 return null;
450             }
451         }
452         LOG.error("NAT Service : Unable to build NaptPacketOut since its not IPv4 packet");
453         return null;
454     }
455
456     private void sendNaptPacketOut(byte[] pktOut, InterfaceInfo infInfo, List<ActionInfo> actionInfos, Long routerId) {
457         LOG.trace("NAT Service: Sending packet out DpId {}, interfaceInfo {}", infInfo.getDpId(), infInfo);
458         // set inPort, and action as OFPP_TABLE so that it starts from table 0 (lowest table as per spec)
459         actionInfos.add(new ActionSetFieldTunnelId(2, BigInteger.valueOf(routerId)));
460         actionInfos.add(new ActionOutput(3, new Uri("0xfffffff9")));
461         NodeConnectorRef inPort = MDSALUtil.getNodeConnRef(infInfo.getDpId(), String.valueOf(infInfo.getPortNo()));
462         LOG.debug("NAT Service : inPort for packetout is being set to {}", String.valueOf(infInfo.getPortNo()));
463         TransmitPacketInput output = MDSALUtil.getPacketOut(actionInfos, pktOut, infInfo.getDpId().longValue(), inPort);
464         LOG.trace("NAT Service: Transmitting packet: {}",output);
465         this.pktService.transmitPacket(output);
466     }
467
468     private String getInterfaceNameFromTag(long portTag) {
469         String interfaceName = null;
470         GetInterfaceFromIfIndexInput input =
471             new GetInterfaceFromIfIndexInputBuilder().setIfIndex(new Integer((int)portTag)).build();
472         Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput =
473             interfaceManagerRpc.getInterfaceFromIfIndex(input);
474         try {
475             GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult();
476             interfaceName = output.getInterfaceName();
477         } catch (InterruptedException | ExecutionException e) {
478             LOG.error("NAT Service : Error while retrieving the interfaceName from tag using "
479                 + "getInterfaceFromIfIndex RPC");
480         }
481         LOG.trace("NAT Service : Returning interfaceName {} for tag {} form getInterfaceNameFromTag",
482             interfaceName, portTag);
483         return interfaceName;
484     }
485 }