Bug 7979: Fix issue where VM is unable to acquire address during IPv6 tests
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / ExternalRoutersListener.java
1 /*
2  * Copyright © 2016, 2017 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 package org.opendaylight.netvirt.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.AsyncFunction;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.JdkFutureAdapters;
15 import com.google.common.util.concurrent.ListenableFuture;
16 import java.math.BigInteger;
17 import java.net.Inet6Address;
18 import java.net.InetAddress;
19 import java.net.UnknownHostException;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Objects;
26 import java.util.Set;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
31 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
32 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
35 import org.opendaylight.genius.mdsalutil.ActionInfo;
36 import org.opendaylight.genius.mdsalutil.BucketInfo;
37 import org.opendaylight.genius.mdsalutil.FlowEntity;
38 import org.opendaylight.genius.mdsalutil.GroupEntity;
39 import org.opendaylight.genius.mdsalutil.InstructionInfo;
40 import org.opendaylight.genius.mdsalutil.MDSALUtil;
41 import org.opendaylight.genius.mdsalutil.MatchInfo;
42 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
43 import org.opendaylight.genius.mdsalutil.NwConstants;
44 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
45 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
46 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
47 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
48 import org.opendaylight.genius.mdsalutil.actions.ActionPuntToController;
49 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
50 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
51 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
52 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
53 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
54 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
55 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
56 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
57 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
58 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
59 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
60 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
61 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
63 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
64 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeGre;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameInputBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.GetTunnelInterfaceNameOutput;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalIpsCounter;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.IntextIpPortMap;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProtocolTypes;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.RouterIdName;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.ExternalCounters;
96 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.ips.counter.external.counters.ExternalIpCounter;
97 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;
98 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapBuilder;
99 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.map.ip.mapping.IpMapKey;
100 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMapping;
101 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.IpPortMappingKey;
102 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.IntextIpProtocolType;
103 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.IpPortMap;
104 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
105 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
106 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchBuilder;
107 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
108 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIds;
109 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsBuilder;
110 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.router.id.name.RouterIdsKey;
111 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
112 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
113 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
114 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
115 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
116 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
117 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
118 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
119 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
120 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
121 import org.opendaylight.yangtools.concepts.ListenerRegistration;
122 import org.opendaylight.yangtools.yang.binding.DataObject;
123 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
124 import org.opendaylight.yangtools.yang.common.RpcResult;
125 import org.slf4j.Logger;
126 import org.slf4j.LoggerFactory;
127
128 public class ExternalRoutersListener extends AsyncDataTreeChangeListenerBase<Routers, ExternalRoutersListener> {
129     private static final Logger LOG = LoggerFactory.getLogger(ExternalRoutersListener.class);
130     private ListenerRegistration<DataChangeListener> listenerRegistration;
131     private final DataBroker dataBroker;
132     private final IMdsalApiManager mdsalManager;
133     private final ItmRpcService itmManager;
134     private final OdlInterfaceRpcService interfaceManager;
135     private final IdManagerService idManager;
136     private final NaptManager naptManager;
137     private final NAPTSwitchSelector naptSwitchSelector;
138     private final IBgpManager bgpManager;
139     private final VpnRpcService vpnService;
140     private final FibRpcService fibService;
141     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
142     private final NaptEventHandler naptEventHandler;
143     private final NaptPacketInHandler naptPacketInHandler;
144     private final IFibManager fibManager;
145     private final IVpnManager vpnManager;
146     private final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer;
147     private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
148     static final BigInteger COOKIE_VM_LFIB_TABLE = new BigInteger("8000022", 16);
149
150     public ExternalRoutersListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
151                                    final ItmRpcService itmManager,
152                                    final OdlInterfaceRpcService interfaceManager,
153                                    final IdManagerService idManager,
154                                    final NaptManager naptManager,
155                                    final NAPTSwitchSelector naptSwitchSelector,
156                                    final IBgpManager bgpManager,
157                                    final VpnRpcService vpnService,
158                                    final FibRpcService fibService,
159                                    final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
160                                    final NaptEventHandler naptEventHandler,
161                                    final NaptPacketInHandler naptPacketInHandler,
162                                    final IFibManager fibManager,
163                                    final IVpnManager vpnManager,
164                                    final EvpnSnatFlowProgrammer evpnSnatFlowProgrammer) {
165         super(Routers.class, ExternalRoutersListener.class);
166         this.dataBroker = dataBroker;
167         this.mdsalManager = mdsalManager;
168         this.itmManager = itmManager;
169         this.interfaceManager = interfaceManager;
170         this.idManager = idManager;
171         this.naptManager = naptManager;
172         this.naptSwitchSelector = naptSwitchSelector;
173         this.bgpManager = bgpManager;
174         this.vpnService = vpnService;
175         this.fibService = fibService;
176         this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
177         this.naptEventHandler = naptEventHandler;
178         this.naptPacketInHandler = naptPacketInHandler;
179         this.fibManager = fibManager;
180         this.vpnManager = vpnManager;
181         this.evpnSnatFlowProgrammer = evpnSnatFlowProgrammer;
182     }
183
184     @Override
185     public void init() {
186         LOG.info("{} init", getClass().getSimpleName());
187         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
188         createGroupIdPool();
189     }
190
191     @Override
192     protected InstanceIdentifier<Routers> getWildCardPath() {
193         return InstanceIdentifier.create(ExtRouters.class).child(Routers.class);
194     }
195
196     @Override
197     // TODO Clean up the exception handling
198     @SuppressWarnings("checkstyle:IllegalCatch")
199     protected void add(InstanceIdentifier<Routers> identifier, Routers routers) {
200         // Populate the router-id-name container
201         String routerName = routers.getRouterName();
202         LOG.info("NAT Service : Add external router event for {}", routerName);
203         NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
204
205         LOG.info("NAT Service : Installing NAT default route on all dpns part of router {}", routerName);
206         try {
207             addOrDelDefFibRouteToSNAT(routerName, true);
208         } catch (Exception ex) {
209             LOG.debug("NAT Service : Exception {} while Installing NAT default route on all dpns part of router {}",
210                 ex, routerName);
211         }
212
213         long segmentId = NatUtil.getVpnId(dataBroker, routerName);
214         // Allocate Primary Napt Switch for this router
215         BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, segmentId);
216         if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
217             LOG.info(
218                     "NAT Service: Failed to get or allocate NAPT switch for router {}. NAPT flow installation will be"
219                     + "delayed", routerName);
220             return;
221         }
222
223         handleRouterGwFlows(routers, primarySwitchId, NwConstants.ADD_FLOW);
224         if (!routers.isEnableSnat()) {
225             LOG.info("NAT Service : SNAT is disabled for external router {} ", routerName);
226             return;
227         }
228
229         handleEnableSnat(routers, segmentId, primarySwitchId);
230     }
231
232     public void handleEnableSnat(Routers routers, long segmentId, BigInteger primarySwitchId) {
233         String routerName = routers.getRouterName();
234         LOG.info("NAT Service : Handling SNAT for router {}", routerName);
235
236         naptManager.initialiseExternalCounter(routers, segmentId);
237         subnetRegisterMapping(routers, segmentId);
238
239         LOG.debug("NAT Service : About to create and install outbound miss entry in Primary Switch {} for router {}",
240             primarySwitchId, routerName);
241
242         long bgpVpnId = NatConstants.INVALID_ID;
243         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
244         if (bgpVpnUuid != null) {
245             bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
246         }
247         if (bgpVpnId != NatConstants.INVALID_ID) {
248             installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, segmentId, false);
249         } else {
250             // write metadata and punt
251             installOutboundMissEntry(routerName, primarySwitchId);
252             // Now install entries in SNAT tables to point to Primary for each router
253             List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
254             if (switches != null) {
255                 for (BigInteger dpnId : switches) {
256                     // Handle switches and NAPT switches separately
257                     if (!dpnId.equals(primarySwitchId)) {
258                         LOG.debug("NAT Service : Handle Ordinary switch");
259                         handleSwitches(dpnId, routerName, primarySwitchId);
260                     } else {
261                         LOG.debug("NAT Service : Handle NAPT switch");
262                         handlePrimaryNaptSwitch(dpnId, routerName);
263                     }
264                 }
265             }
266         }
267
268         List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, segmentId);
269         if (externalIps == null || externalIps.isEmpty()) {
270             LOG.debug("NAT Service : Internal External mapping found for router {}", routerName);
271             return;
272         } else {
273             for (String externalIpAddrPrefix : externalIps) {
274                 LOG.debug("NAT Service : Calling handleSnatReverseTraffic for primarySwitchId {}, "
275                     + "routerName {} and externalIpAddPrefix {}", primarySwitchId, routerName, externalIpAddrPrefix);
276                 handleSnatReverseTraffic(primarySwitchId, routers, segmentId, routerName, externalIpAddrPrefix);
277             }
278         }
279         LOG.info("NAT Service : handleEnableSnat() Exit");
280     }
281
282     private BigInteger getPrimaryNaptSwitch(String routerName, long segmentId) {
283         // Allocate Primary Napt Switch for this router
284         BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
285         if (primarySwitchId != null && !primarySwitchId.equals(BigInteger.ZERO)) {
286             LOG.debug("NAT Service : Primary NAPT switch with DPN ID {} is already elected for router",
287                 primarySwitchId, routerName);
288             return primarySwitchId;
289         }
290
291         primarySwitchId = naptSwitchSelector.selectNewNAPTSwitch(routerName);
292         LOG.debug("NAT Service : Primary NAPT switch DPN ID {}", primarySwitchId);
293         if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
294             LOG.info("NAT Service : Unable to to select the primary NAPT switch for router {}", routerName);
295         }
296
297         return primarySwitchId;
298     }
299
300     protected void installNaptPfibExternalOutputFlow(String routerName, Long routerId, BigInteger dpnId) {
301         Long extVpnId = NatUtil.getVpnId(dataBroker, routerId);
302         if (extVpnId == null || extVpnId == NatConstants.INVALID_ID) {
303             LOG.debug("installNaptPfibExternalOutputFlow - not found extVpnId for router {}", routerId);
304             extVpnId = routerId;
305         }
306         List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerName);
307         if (externalIps == null || externalIps.isEmpty()) {
308             LOG.debug("installNaptPfibExternalOutputFlow - empty external Ips list for dpnId {} extVpnId {}",
309                 dpnId, extVpnId);
310             return;
311         }
312         for (String ip : externalIps) {
313             Uuid subnetId = getSubnetIdForFixedIp(ip);
314             if (subnetId != null) {
315                 long subnetVpnId = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
316                 if (subnetVpnId != NatConstants.INVALID_ID) {
317                     extVpnId = subnetVpnId;
318                 }
319                 LOG.debug("installNaptPfibExternalOutputFlow - dpnId {} extVpnId {} subnetId {}",
320                     dpnId, extVpnId, subnetId);
321                 FlowEntity postNaptFlowEntity = buildNaptPfibFlowEntity(dpnId, extVpnId);
322                 mdsalManager.installFlow(postNaptFlowEntity);
323             }
324         }
325     }
326
327     private Uuid getSubnetIdForFixedIp(String ip) {
328         if (ip != null) {
329             IpAddress externalIpv4Address = new IpAddress(new Ipv4Address(ip));
330             Port port = NatUtil.getNeutronPortForRouterGetewayIp(dataBroker, externalIpv4Address);
331             Uuid subnetId = NatUtil.getSubnetIdForFloatingIp(port, externalIpv4Address);
332             return subnetId;
333         }
334         return null;
335     }
336
337     protected void subnetRegisterMapping(Routers routerEntry, Long segmentId) {
338         List<Uuid> subnetList = null;
339         List<String> externalIps = null;
340         LOG.debug("NAT Service : Fetching values from extRouters model");
341         subnetList = routerEntry.getSubnetIds();
342         externalIps = NatUtil.getIpsListFromExternalIps(routerEntry.getExternalIps());
343         int counter = 0;
344         int extIpCounter = externalIps.size();
345         LOG.debug("NAT Service : counter values before looping counter {} and extIpCounter {}", counter, extIpCounter);
346         for (Uuid subnet : subnetList) {
347             LOG.debug("NAT Service : Looping internal subnets for subnet {}", subnet);
348             InstanceIdentifier<Subnetmap> subnetmapId = InstanceIdentifier
349                 .builder(Subnetmaps.class)
350                 .child(Subnetmap.class, new SubnetmapKey(subnet))
351                 .build();
352             Optional<Subnetmap> sn = read(dataBroker, LogicalDatastoreType.CONFIGURATION, subnetmapId);
353             if (sn.isPresent()) {
354                 // subnets
355                 Subnetmap subnetmapEntry = sn.get();
356                 String subnetString = subnetmapEntry.getSubnetIp();
357                 String[] subnetSplit = subnetString.split("/");
358                 String subnetIp = subnetSplit[0];
359                 try {
360                     InetAddress address = InetAddress.getByName(subnetIp);
361                     if (address instanceof Inet6Address) {
362                         // TODO: Revisit when IPv6 external connectivity support is added.
363                         LOG.debug("Skipping ipv6 address {}.", address);
364                         return;
365                     }
366                 } catch (UnknownHostException e) {
367                     LOG.warn("Invalid ip address {}", subnetIp, e);
368                     return;
369                 }
370                 String subnetPrefix = "0";
371                 if (subnetSplit.length == 2) {
372                     subnetPrefix = subnetSplit[1];
373                 }
374                 IPAddress subnetAddr = new IPAddress(subnetIp, Integer.parseInt(subnetPrefix));
375                 LOG.debug("NAT Service : subnetAddr is {} and subnetPrefix is {}",
376                     subnetAddr.getIpAddress(), subnetAddr.getPrefixLength());
377                 //externalIps
378                 LOG.debug("NAT Service : counter values counter {} and extIpCounter {}", counter, extIpCounter);
379                 if (extIpCounter != 0) {
380                     if (counter < extIpCounter) {
381                         String[] ipSplit = externalIps.get(counter).split("/");
382                         String externalIp = ipSplit[0];
383                         String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
384                         if (ipSplit.length == 2) {
385                             extPrefix = ipSplit[1];
386                         }
387                         IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
388                         LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}",
389                             externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
390                         naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
391                         LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. "
392                             + "prefix {}", subnetIp, subnetPrefix, externalIp, extPrefix);
393                     } else {
394                         counter = 0;    //Reset the counter which runs on externalIps for round-robbin effect
395                         LOG.debug("NAT Service : Counter on externalIps got reset");
396                         String[] ipSplit = externalIps.get(counter).split("/");
397                         String externalIp = ipSplit[0];
398                         String extPrefix = Short.toString(NatConstants.DEFAULT_PREFIX);
399                         if (ipSplit.length == 2) {
400                             extPrefix = ipSplit[1];
401                         }
402                         IPAddress externalIpAddr = new IPAddress(externalIp, Integer.parseInt(extPrefix));
403                         LOG.debug("NAT Service : externalIp is {} and extPrefix  is {}",
404                             externalIpAddr.getIpAddress(), externalIpAddr.getPrefixLength());
405                         naptManager.registerMapping(segmentId, subnetAddr, externalIpAddr);
406                         LOG.debug("NAT Service : Called registerMapping for subnetIp {}, prefix {}, externalIp {}. "
407                                 + "prefix {}", subnetIp, subnetPrefix,
408                             externalIp, extPrefix);
409                     }
410                 }
411                 counter++;
412                 LOG.debug("NAT Service : Counter on externalIps incremented to {}", counter);
413             } else {
414                 LOG.warn("NAT Service : No internal subnets present in extRouters Model");
415             }
416         }
417     }
418
419     private void addOrDelDefFibRouteToSNAT(String routerName, boolean create) {
420         //Check if BGP VPN exists. If exists then invoke the new method.
421         long bgpVpnId = NatUtil.getBgpVpnId(dataBroker, routerName);
422         if (bgpVpnId != NatConstants.INVALID_ID) {
423             Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
424             if (bgpVpnUuid != null) {
425                 String bgpVpnName = bgpVpnUuid.getValue();
426                 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
427                     bgpVpnId, bgpVpnName);
428                 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId))
429                     .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
430                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
431                     getRoutersIdentifier(bgpVpnId), rtrs);
432             }
433             addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, bgpVpnId, create);
434             return;
435         }
436
437         //Router ID is used as the internal VPN's name, hence the vrf-id in VpnInstance Op DataStore
438         addOrDelDefaultFibRouteForSNAT(routerName, create);
439     }
440
441     private void addOrDelDefaultFibRouteForSNAT(String routerName, boolean create) {
442         List<BigInteger> switches = naptSwitchSelector.getDpnsForVpn(routerName);
443         if (switches == null || switches.isEmpty()) {
444             LOG.debug("No switches found for router {}", routerName);
445             return;
446         }
447         long routerId = NatUtil.readVpnId(dataBroker, routerName);
448         if (routerId == NatConstants.INVALID_ID) {
449             LOG.error("Could not retrieve router Id for {} to program default NAT route in FIB", routerName);
450             return;
451         }
452         for (BigInteger dpnId : switches) {
453             if (create) {
454                 LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} for the internal vpn",
455                     routerId, dpnId);
456                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
457             } else {
458                 LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} for the internal vpn",
459                     routerId, dpnId);
460                 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
461             }
462         }
463     }
464
465     private void addOrDelDefaultFibRouteForSnatWithBgpVpn(String routerName, long bgpVpnId, boolean create) {
466         List<BigInteger> dpnIds = NatUtil.getDpnsForRouter(dataBroker, routerName);
467         if (dpnIds == null || dpnIds.isEmpty()) {
468             LOG.debug("NAT Service : Current no dpns part of router {} to program default NAT route", routerName);
469             return;
470         }
471         long routerId = NatUtil.getVpnId(dataBroker, routerName);
472         for (BigInteger dpnId : dpnIds) {
473             if (create) {
474                 if (bgpVpnId != NatConstants.INVALID_ID) {
475                     LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} "
476                         + "for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
477                     defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
478                 } else {
479                     LOG.debug("NAT Service : installing default NAT route for router {} in dpn {} "
480                         + "for the internal vpn", routerId, dpnId);
481                     defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId);
482                 }
483             } else {
484                 if (bgpVpnId != NatConstants.INVALID_ID) {
485                     LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} "
486                         + "for the BGP vpnID {}", routerId, dpnId, bgpVpnId);
487                     defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, bgpVpnId, routerId);
488                 } else {
489                     LOG.debug("NAT Service : removing default NAT route for router {} in dpn {} "
490                         + "for the internal vpn", routerId, dpnId);
491                     defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId);
492                 }
493             }
494         }
495     }
496
497     // TODO Clean up the exception handling
498     @SuppressWarnings("checkstyle:IllegalCatch")
499     public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
500                                                           InstanceIdentifier<T> path) {
501         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
502
503         try {
504             return tx.read(datastoreType, path).get();
505         } catch (Exception e) {
506             throw new RuntimeException(e);
507         }
508     }
509
510     // TODO Clean up the exception handling
511     @SuppressWarnings("checkstyle:IllegalCatch")
512     @Override
513     public void close() {
514         if (listenerRegistration != null) {
515             try {
516                 listenerRegistration.close();
517             } catch (final Exception e) {
518                 LOG.error("Error when cleaning up ExternalRoutersListener.", e);
519             }
520
521             listenerRegistration = null;
522         }
523         LOG.debug("ExternalRoutersListener Closed");
524     }
525
526     protected void installOutboundMissEntry(String routerName, BigInteger primarySwitchId) {
527         long routerId = NatUtil.getVpnId(dataBroker, routerName);
528         LOG.debug("NAT Service : Router ID from getVpnId {}", routerId);
529         if (routerId != NatConstants.INVALID_ID) {
530             LOG.debug("NAT Service : Creating miss entry on primary {}, for router {}", primarySwitchId, routerId);
531             createOutboundTblEntry(primarySwitchId, routerId);
532         } else {
533             LOG.error("NAT Service : Unable to fetch Router Id  for RouterName {}, failed to "
534                 + "createAndInstallMissEntry", routerName);
535         }
536     }
537
538     public String getFlowRefOutbound(BigInteger dpnId, short tableId, long routerID) {
539         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
540                 .FLOWID_SEPARATOR + routerID;
541     }
542
543     private String getFlowRefNaptFib(BigInteger dpnId, short tableId, long routerID, String externalIp) {
544         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
545                 .FLOWID_SEPARATOR + routerID + NatConstants.FLOWID_SEPARATOR + externalIp;
546     }
547
548     public BigInteger getCookieOutboundFlow(long routerId) {
549         return NwConstants.COOKIE_OUTBOUND_NAPT_TABLE.add(new BigInteger("0110001", 16)).add(
550             BigInteger.valueOf(routerId));
551     }
552
553     protected FlowEntity buildOutboundFlowEntity(BigInteger dpId, long routerId) {
554         LOG.debug("NAT Service : buildOutboundFlowEntity called for dpId {} and routerId{}", dpId, routerId);
555         List<MatchInfo> matches = new ArrayList<>();
556         matches.add(MatchEthernetType.IPV4);
557         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
558
559         List<InstructionInfo> instructions = new ArrayList<>();
560         List<ActionInfo> actionsInfos = new ArrayList<>();
561         actionsInfos.add(new ActionPuntToController());
562         instructions.add(new InstructionApplyActions(actionsInfos));
563         instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
564             MetaDataUtil.METADATA_MASK_VRFID));
565
566         String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
567         BigInteger cookie = getCookieOutboundFlow(routerId);
568         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE, flowRef,
569             5, flowRef, 0, 0,
570             cookie, matches, instructions);
571         LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
572         return flowEntity;
573     }
574
575     public void createOutboundTblEntry(BigInteger dpnId, long routerId) {
576         LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}", dpnId, routerId);
577         FlowEntity flowEntity = buildOutboundFlowEntity(dpnId, routerId);
578         LOG.debug("NAT Service : Installing flow {}", flowEntity);
579         mdsalManager.installFlow(flowEntity);
580     }
581
582     protected String getTunnelInterfaceName(BigInteger srcDpId, BigInteger dstDpId) {
583         Class<? extends TunnelTypeBase> tunType = TunnelTypeVxlan.class;
584         RpcResult<GetTunnelInterfaceNameOutput> rpcResult;
585         try {
586             Future<RpcResult<GetTunnelInterfaceNameOutput>> result =
587                 itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
588                     .setSourceDpid(srcDpId)
589                     .setDestinationDpid(dstDpId)
590                     .setTunnelType(tunType)
591                     .build());
592             rpcResult = result.get();
593             if (!rpcResult.isSuccessful()) {
594                 tunType = TunnelTypeGre.class;
595                 result = itmManager.getTunnelInterfaceName(new GetTunnelInterfaceNameInputBuilder()
596                     .setSourceDpid(srcDpId)
597                     .setDestinationDpid(dstDpId)
598                     .setTunnelType(tunType)
599                     .build());
600                 rpcResult = result.get();
601                 if (!rpcResult.isSuccessful()) {
602                     LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
603                 } else {
604                     return rpcResult.getResult().getInterfaceName();
605                 }
606                 LOG.warn("RPC Call to getTunnelInterfaceId returned with Errors {}", rpcResult.getErrors());
607             } else {
608                 return rpcResult.getResult().getInterfaceName();
609             }
610         } catch (InterruptedException | ExecutionException | NullPointerException e) {
611             LOG.warn("NAT Service : Exception when getting tunnel interface Id for tunnel between {} and  {}",
612                 srcDpId, dstDpId);
613         }
614
615         return null;
616     }
617
618     protected void installSnatMissEntryForPrimrySwch(BigInteger dpnId, String routerName) {
619         LOG.debug("NAT Service : installSnatMissEntry called for for the primary NAPT switch dpnId {} ", dpnId);
620         // Install miss entry pointing to group
621         FlowEntity flowEntity = buildSnatFlowEntityForPrmrySwtch(dpnId, routerName);
622         mdsalManager.installFlow(flowEntity);
623     }
624
625     protected void installSnatMissEntry(BigInteger dpnId, List<BucketInfo> bucketInfo, String routerName) {
626         LOG.debug("NAT Service : installSnatMissEntry called for dpnId {} with primaryBucket {} ",
627             dpnId, bucketInfo.get(0));
628         // Install the select group
629         long groupId = createGroupId(getGroupIdKey(routerName));
630         GroupEntity groupEntity =
631             MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
632         LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
633         mdsalManager.syncInstallGroup(groupEntity, 0);
634         // Install miss entry pointing to group
635         FlowEntity flowEntity = buildSnatFlowEntity(dpnId, routerName, groupId);
636         if (flowEntity == null) {
637             LOG.error("NAT Service : Flow entity received as NULL. "
638                     + "Cannot proceed with installation of SNAT Flow in table {} which is pointing to Group "
639                     + "on Non NAPT DPN {} for router {}", NwConstants.PSNAT_TABLE, dpnId, routerName);
640             return;
641         }
642         mdsalManager.installFlow(flowEntity);
643     }
644
645     long installGroup(BigInteger dpnId, String routerName, List<BucketInfo> bucketInfo) {
646         long groupId = createGroupId(getGroupIdKey(routerName));
647         GroupEntity groupEntity =
648             MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, bucketInfo);
649         LOG.debug("NAT Service : installing the SNAT to NAPT GroupEntity:{}", groupEntity);
650         mdsalManager.syncInstallGroup(groupEntity, 0);
651         return groupId;
652     }
653
654     public FlowEntity buildSnatFlowEntity(BigInteger dpId, String routerName, long groupId) {
655         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} and groupId {}",
656                 dpId, routerName, groupId);
657         long routerId = NatUtil.getVpnId(dataBroker, routerName);
658         List<MatchInfo> matches = new ArrayList<>();
659         matches.add(MatchEthernetType.IPV4);
660         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
661
662         List<ActionInfo> actionsInfo = new ArrayList<>();
663         long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
664         actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(tunnelId)));
665         LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
666         actionsInfo.add(new ActionGroup(groupId));
667         List<InstructionInfo> instructions = new ArrayList<>();
668         instructions.add(new InstructionApplyActions(actionsInfo));
669         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
670         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
671                 NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
672                 NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
673
674         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
675         return flowEntity;
676     }
677
678     public FlowEntity buildSnatFlowEntityForPrmrySwtch(BigInteger dpId, String routerName) {
679
680         LOG.debug("NAT Service : buildSnatFlowEntity is called for primary NAPT switch dpId {}, routerName {}", dpId,
681             routerName);
682         long routerId = NatUtil.getVpnId(dataBroker, routerName);
683         List<MatchInfo> matches = new ArrayList<>();
684         matches.add(MatchEthernetType.IPV4);
685         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(routerId), MetaDataUtil.METADATA_MASK_VRFID));
686
687         List<InstructionInfo> instructions = new ArrayList<>();
688         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
689
690         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
691         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
692             NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
693             NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
694
695         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
696         return flowEntity;
697     }
698
699     // TODO : Replace this with ITM Rpc once its available with full functionality
700     protected void installTerminatingServiceTblEntry(BigInteger dpnId, String routerName) {
701         LOG.debug("NAT Service : creating entry for Terminating Service Table for switch {}, routerName {}",
702             dpnId, routerName);
703         FlowEntity flowEntity = buildTsFlowEntity(dpnId, routerName);
704         if (flowEntity == null) {
705             LOG.error("NAT Service : Flow entity received as NULL. "
706                     + "Cannot proceed with installation of Terminating Service table {} which is pointing to table {} "
707                     + "on DPN {} for router {}", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.OUTBOUND_NAPT_TABLE,
708                     dpnId, routerName);
709             return;
710         }
711         mdsalManager.installFlow(flowEntity);
712
713     }
714
715     private FlowEntity buildTsFlowEntity(BigInteger dpId, String routerName) {
716         long routerId = NatUtil.getVpnId(dataBroker, routerName);
717         List<MatchInfo> matches = new ArrayList<>();
718         matches.add(MatchEthernetType.IPV4);
719         long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
720         matches.add(new MatchTunnelId(BigInteger.valueOf(tunnelId)));
721         String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
722
723         List<InstructionInfo> instructions = new ArrayList<>();
724         instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(routerId),
725                 MetaDataUtil.METADATA_MASK_VRFID));
726         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
727         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
728                 NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0, NwConstants.COOKIE_TS_TABLE, matches,
729                 instructions);
730         return flowEntity;
731     }
732
733     public String getFlowRefTs(BigInteger dpnId, short tableId, long routerID) {
734         return NatConstants.NAPT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
735                 .FLOWID_SEPARATOR + routerID;
736     }
737
738     public static String getFlowRefSnat(BigInteger dpnId, short tableId, String routerID) {
739         return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NatConstants.FLOWID_SEPARATOR + tableId + NatConstants
740                 .FLOWID_SEPARATOR + routerID;
741     }
742
743     private String getGroupIdKey(String routerName) {
744         return "snatmiss." + routerName;
745     }
746
747     protected long createGroupId(String groupIdKey) {
748         AllocateIdInput getIdInput = new AllocateIdInputBuilder()
749             .setPoolName(NatConstants.SNAT_IDPOOL_NAME).setIdKey(groupIdKey)
750             .build();
751         try {
752             Future<RpcResult<AllocateIdOutput>> result = idManager.allocateId(getIdInput);
753             RpcResult<AllocateIdOutput> rpcResult = result.get();
754             return rpcResult.getResult().getIdValue();
755         } catch (NullPointerException | InterruptedException | ExecutionException e) {
756             LOG.trace("", e);
757         }
758         return 0;
759     }
760
761     protected void createGroupIdPool() {
762         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
763             .setPoolName(NatConstants.SNAT_IDPOOL_NAME)
764             .setLow(NatConstants.SNAT_ID_LOW_VALUE)
765             .setHigh(NatConstants.SNAT_ID_HIGH_VALUE)
766             .build();
767         try {
768             Future<RpcResult<Void>> result = idManager.createIdPool(createPool);
769             if ((result != null) && (result.get().isSuccessful())) {
770                 LOG.debug("NAT Service : Created GroupIdPool");
771             } else {
772                 LOG.error("NAT Service : Unable to create GroupIdPool");
773             }
774         } catch (InterruptedException | ExecutionException e) {
775             LOG.error("Failed to create PortPool for NAPT Service", e);
776         }
777     }
778
779     protected void handleSwitches(BigInteger dpnId, String routerName, BigInteger primarySwitchId) {
780         LOG.debug("NAT Service : Installing SNAT miss entry in switch {}", dpnId);
781         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
782         String ifNamePrimary = getTunnelInterfaceName(dpnId, primarySwitchId);
783         List<BucketInfo> listBucketInfo = new ArrayList<>();
784         long routerId = NatUtil.getVpnId(dataBroker, routerName);
785
786         if (ifNamePrimary != null) {
787             LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
788             listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
789         }
790         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
791
792         listBucketInfo.add(0, bucketPrimary);
793         installSnatMissEntry(dpnId, listBucketInfo, routerName);
794     }
795
796     List<BucketInfo> getBucketInfoForNonNaptSwitches(BigInteger nonNaptSwitchId,
797                                                      BigInteger primarySwitchId, String routerName) {
798         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
799         String ifNamePrimary = getTunnelInterfaceName(nonNaptSwitchId, primarySwitchId);
800         List<BucketInfo> listBucketInfo = new ArrayList<>();
801         long routerId = NatUtil.getVpnId(dataBroker, routerName);
802
803         if (ifNamePrimary != null) {
804             LOG.debug("NAT Service : On Non- Napt switch , Primary Tunnel interface is {}", ifNamePrimary);
805             listActionInfoPrimary = NatUtil.getEgressActionsForInterface(interfaceManager, ifNamePrimary, routerId);
806         }
807         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
808
809         listBucketInfo.add(0, bucketPrimary);
810         return listBucketInfo;
811     }
812
813     protected void handlePrimaryNaptSwitch(BigInteger dpnId, String routerName) {
814        /*
815         * Primary NAPT Switch â€“ bucket Should always point back to its own Outbound Table
816         */
817
818         LOG.debug("NAT Service : Installing SNAT miss entry in Primary NAPT switch {} ", dpnId);
819
820 /*
821         List<BucketInfo> listBucketInfo = new ArrayList<>();
822         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
823         listActionInfoPrimary.add(new ActionNxResubmit(NatConstants.TERMINATING_SERVICE_TABLE));
824         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
825         listBucketInfo.add(0, bucketPrimary);
826 */
827
828         long routerId = NatUtil.getVpnId(dataBroker, routerName);
829
830         installSnatMissEntryForPrimrySwch(dpnId, routerName);
831         installTerminatingServiceTblEntry(dpnId, routerName);
832         //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the router ID.
833         installNaptPfibEntry(dpnId, routerId);
834         Long vpnId = NatUtil.getVpnId(dataBroker, routerName);
835         installNaptPfibEntriesForExternalSubnets(routerName, dpnId);
836         //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
837         if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
838             installNaptPfibEntry(dpnId, vpnId);
839         }
840     }
841
842     List<BucketInfo> getBucketInfoForPrimaryNaptSwitch() {
843         List<BucketInfo> listBucketInfo = new ArrayList<>();
844         List<ActionInfo> listActionInfoPrimary = new ArrayList<>();
845         listActionInfoPrimary.add(new ActionNxResubmit(NwConstants.INTERNAL_TUNNEL_TABLE));
846         BucketInfo bucketPrimary = new BucketInfo(listActionInfoPrimary);
847         listBucketInfo.add(0, bucketPrimary);
848         return listBucketInfo;
849     }
850
851     public void installNaptPfibEntry(BigInteger dpnId, long segmentId) {
852         LOG.debug("NAT Service : installNaptPfibEntry called for dpnId {} and segmentId {} ", dpnId, segmentId);
853         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntity(dpnId, segmentId);
854         mdsalManager.installFlow(naptPfibFlowEntity);
855     }
856
857     public FlowEntity buildNaptPfibFlowEntity(BigInteger dpId, long segmentId) {
858
859         LOG.debug("NAT Service : buildNaptPfibFlowEntity is called for dpId {}, segmentId {}", dpId, segmentId);
860         List<MatchInfo> matches = new ArrayList<>();
861         matches.add(MatchEthernetType.IPV4);
862         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
863
864         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
865         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
866         listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
867         listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
868         instructionInfo.add(new InstructionApplyActions(listActionInfo));
869
870         String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
871         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
872             NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
873             NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
874         LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
875         return flowEntity;
876     }
877
878     private void handleSnatReverseTraffic(BigInteger dpnId, Routers router, long routerId, String routerName,
879             String externalIp) {
880         LOG.debug("NAT Service : handleSnatReverseTraffic() entry for DPN ID, routerId, externalIp: {}",
881             dpnId, routerId, externalIp);
882         Uuid networkId = NatUtil.getNetworkIdFromRouterId(dataBroker, routerId);
883         if (networkId == null) {
884             LOG.error("NAT Service : networkId is null for the router ID {}", routerId);
885             return;
886         }
887         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
888         if (vpnName == null) {
889             LOG.error("NAT Service : No VPN associated with ext nw {} to handle add external ip "
890                     + "configuration {} in router {}",
891                 networkId, externalIp, routerId);
892             return;
893         }
894         advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
895             externalIp, router, vpnService, fibService, bgpManager, dataBroker, LOG);
896         LOG.debug("NAT Service : handleSnatReverseTraffic() exit for DPN ID, routerId, externalIp : {}",
897             dpnId, routerId, externalIp);
898     }
899
900     public void advToBgpAndInstallFibAndTsFlows(final BigInteger dpnId, final short tableId, final String vpnName,
901                                                 final long routerId, final String routerName, final String externalIp,
902                                                 final Routers router, VpnRpcService vpnService,
903                                                 final FibRpcService fibService, final IBgpManager bgpManager,
904                                                 final DataBroker dataBroker, final Logger log) {
905         LOG.debug("NAT Service : advToBgpAndInstallFibAndTsFlows() entry for DPN ID {}, tableId {}, vpnname {} "
906                 + "and externalIp {}", dpnId, tableId, vpnName, externalIp);
907         String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
908         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
909         if (rd == null || rd.isEmpty()) {
910             LOG.error("NAT Service : Unable to get RD for VPN Name {}", vpnName);
911             return;
912         }
913         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
914         if (extNwProvType == null) {
915             return;
916         }
917         if (extNwProvType == ProviderTypes.VXLAN) {
918             WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
919             evpnSnatFlowProgrammer.evpnAdvToBgpAndInstallFibAndTsFlows(dpnId, tableId, externalIp, vpnName, rd,
920                     nextHopIp, writeTx, routerId);
921             return;
922         }
923         //Generate VPN label for the external IP
924         GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
925             .setIpPrefix(externalIp).build();
926         Future<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
927
928         //On successful generation of the VPN label, advertise the route to the BGP and install the FIB routes.
929         ListenableFuture<RpcResult<Void>> future =
930             Futures.transform(JdkFutureAdapters.listenInPoolThread(labelFuture),
931                 (AsyncFunction<RpcResult<GenerateVpnLabelOutput>, RpcResult<Void>>) result -> {
932                     if (result.isSuccessful()) {
933                         LOG.debug("NAT Service : inside apply with result success");
934                         GenerateVpnLabelOutput output = result.getResult();
935                         final long label = output.getLabel();
936
937                         int externalIpInDsFlag = 0;
938                         //Get IPMaps from the DB for the router ID
939                         List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
940                         if (dbIpMaps != null) {
941                             for (IpMap dbIpMap : dbIpMaps) {
942                                 String dbExternalIp = dbIpMap.getExternalIp();
943                                 //Select the IPMap, whose external IP is the IP for which FIB is installed
944                                 if (dbExternalIp.contains(externalIp)) {
945                                     String dbInternalIp = dbIpMap.getInternalIp();
946                                     IpMapKey dbIpMapKey = dbIpMap.getKey();
947                                     LOG.debug("Setting label {} for internalIp {} and externalIp {}",
948                                         label, dbInternalIp, externalIp);
949                                     IpMap newIpm = new IpMapBuilder().setKey(dbIpMapKey).setInternalIp(dbInternalIp)
950                                         .setExternalIp(dbExternalIp).setLabel(label).build();
951                                     MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
952                                         naptManager.getIpMapIdentifier(routerId, dbInternalIp), newIpm);
953                                     externalIpInDsFlag++;
954                                 }
955                             }
956                             if (externalIpInDsFlag <= 0) {
957                                 LOG.debug("NAT Service : External Ip {} not found in DS, Failed to update label {} "
958                                     + "for routerId {} in DS", externalIp, label, routerId);
959                                 String errMsg = String.format("Failed to update label %s due to external Ip %s not"
960                                     + " found in DS for router %s", label, externalIp, routerId);
961                                 return Futures.immediateFailedFuture(new Exception(errMsg));
962                             }
963                         } else {
964                             LOG.error("NAT Service : Failed to write label {} for externalIp {} for "
965                                     + "routerId {} in DS", label, externalIp, routerId);
966                         }
967                         //Inform BGP
968                         Routers extRouter = router != null ? router :
969                             NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
970                         Uuid externalSubnetId = NatUtil.getExternalSubnetForRouterExternalIp(dataBroker, externalIp,
971                                 router);
972                         NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, externalSubnetId,
973                             externalIp, nextHopIp, router.getNetworkId().getValue(), null, label, log,
974                             RouteOrigin.STATIC, dpnId);
975
976                         //Install custom FIB routes
977                         List<Instruction> tunnelTableCustomInstructions = new ArrayList<>();
978                         tunnelTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(0));
979                         makeTunnelTableEntry(dpnId, label, tunnelTableCustomInstructions);
980                         makeLFibTableEntry(dpnId, label, tableId);
981
982                         //Install custom FIB routes - FIB table.
983                         List<Instruction> fibTableCustomInstructions = createFibTableCustomInstructions(dataBroker,
984                                 tableId, routerName, externalIp);
985                         String fibExternalIp = externalIp.contains("/32") ? externalIp : (externalIp + "/32");
986                         CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
987                             .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
988                             .setInstruction(fibTableCustomInstructions).build();
989                         Future<RpcResult<Void>> future1 = fibService.createFibEntry(input);
990                         return JdkFutureAdapters.listenInPoolThread(future1);
991                     } else {
992                         LOG.error("NAT Service : inside apply with result failed");
993                         String errMsg = String.format("Could not retrieve the label for prefix %s in VPN %s, %s",
994                             externalIp, vpnName, result.getErrors());
995                         return Futures.immediateFailedFuture(new RuntimeException(errMsg));
996                     }
997                 });
998
999         Futures.addCallback(future, new FutureCallback<RpcResult<Void>>() {
1000
1001             @Override
1002             public void onFailure(Throwable error) {
1003                 log.error("NAT Service : Error in generate label or fib install process", error);
1004             }
1005
1006             @Override
1007             public void onSuccess(RpcResult<Void> result) {
1008                 if (result.isSuccessful()) {
1009                     log.info("NAT Service : Successfully installed custom FIB routes for prefix {}", externalIp);
1010                 } else {
1011                     log.error("NAT Service : Error in rpc call to create custom Fib entries for prefix {} in "
1012                         + "DPN {}, {}", externalIp, dpnId, result.getErrors());
1013                 }
1014             }
1015         });
1016     }
1017
1018     private List<Instruction> createFibTableCustomInstructions(DataBroker dataBroker, short tableId,
1019             String routerName, String externalIp) {
1020         List<Instruction> fibTableCustomInstructions = new ArrayList<>();
1021         Routers router = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
1022         long externalSubnetVpnId = NatUtil.getExternalSubnetVpnIdForRouterExternalIp(dataBroker,
1023                 externalIp, router);
1024         int instructionIndex = 0;
1025         if (externalSubnetVpnId != NatConstants.INVALID_ID) {
1026             BigInteger subnetIdMetaData = MetaDataUtil.getVpnIdMetadata(externalSubnetVpnId);
1027             fibTableCustomInstructions.add(new InstructionWriteMetadata(subnetIdMetaData,
1028                     MetaDataUtil.METADATA_MASK_VRFID).buildInstruction(instructionIndex));
1029             instructionIndex++;
1030         }
1031
1032         fibTableCustomInstructions.add(new InstructionGotoTable(tableId).buildInstruction(instructionIndex));
1033         return fibTableCustomInstructions;
1034     }
1035
1036     private void makeLFibTableEntry(BigInteger dpId, long serviceId, short tableId) {
1037         List<MatchInfo> matches = new ArrayList<>();
1038         matches.add(MatchEthernetType.MPLS_UNICAST);
1039         matches.add(new MatchMplsLabel(serviceId));
1040
1041         List<Instruction> instructions = new ArrayList<>();
1042         List<ActionInfo> actionsInfos = new ArrayList<>();
1043         actionsInfos.add(new ActionPopMpls());
1044         Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
1045         instructions.add(writeInstruction);
1046         instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
1047
1048         // Install the flow entry in L3_LFIB_TABLE
1049         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
1050
1051         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
1052             10, flowRef, 0, 0,
1053             COOKIE_VM_LFIB_TABLE, matches, instructions);
1054
1055         mdsalManager.installFlow(dpId, flowEntity);
1056
1057         LOG.debug("NAT Service : LFIB Entry for dpID {} : label : {} modified successfully {}", dpId, serviceId);
1058     }
1059
1060     private void makeTunnelTableEntry(BigInteger dpnId, long serviceId, List<Instruction> customInstructions) {
1061         List<MatchInfo> mkMatches = new ArrayList<>();
1062
1063         LOG.debug("NAT Service : Create terminatingServiceAction on DpnId = {} and serviceId = {} and actions = {}",
1064             dpnId, serviceId);
1065
1066         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
1067
1068         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
1069             getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), 5,
1070             String.format("%s:%d", "TST Flow Entry ", serviceId),
1071             0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
1072
1073         mdsalManager.installFlow(dpnId, terminatingServiceTableFlowEntity);
1074     }
1075
1076     protected InstanceIdentifier<RouterIds> getRoutersIdentifier(long routerId) {
1077         InstanceIdentifier<RouterIds> id = InstanceIdentifier.builder(
1078             RouterIdName.class).child(RouterIds.class, new RouterIdsKey(routerId)).build();
1079         return id;
1080     }
1081
1082     private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
1083         return NatConstants.SNAT_FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants
1084                 .FLOWID_SEPARATOR + id + NwConstants.FLOWID_SEPARATOR + ipAddress;
1085     }
1086
1087     @Override
1088     protected void update(InstanceIdentifier<Routers> identifier, Routers original, Routers update) {
1089         String routerName = original.getRouterName();
1090         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1091         if (routerId == NatConstants.INVALID_ID) {
1092             LOG.error("NAT Service : Update external router event - Invalid routerId for routerName {}", routerName);
1093             return;
1094         }
1095         BigInteger dpnId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1096         Uuid networkId = original.getNetworkId();
1097
1098         // Check if its update on SNAT flag
1099         boolean originalSNATEnabled = original.isEnableSnat();
1100         boolean updatedSNATEnabled = update.isEnableSnat();
1101         LOG.debug("NAT Service : update of externalRoutersListener called with originalFlag and updatedFlag "
1102             + "as {} and {}", originalSNATEnabled, updatedSNATEnabled);
1103         if (originalSNATEnabled != updatedSNATEnabled) {
1104             if (originalSNATEnabled) {
1105                 //SNAT disabled for the router
1106                 Uuid networkUuid = original.getNetworkId();
1107                 LOG.info("NAT Service : SNAT disabled for Router {}", routerName);
1108                 List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1109                 handleDisableSnat(original, networkUuid, externalIps, false, null, dpnId);
1110             } else {
1111                 // Allocate Primary Napt Switch for existing router
1112                 BigInteger primarySwitchId = getPrimaryNaptSwitch(routerName, routerId);
1113                 if (primarySwitchId == null || primarySwitchId.equals(BigInteger.ZERO)) {
1114                     LOG.error("NAT Service: Failed to get or allocated NAPT switch in ExternalRouterListener.Update()");
1115                     return;
1116                 }
1117                 LOG.info("NAT Service : SNAT enabled for Router {}", original.getRouterName());
1118                 handleEnableSnat(original, routerId, primarySwitchId);
1119             }
1120         }
1121
1122         if (!Objects.equals(original.getExtGwMacAddress(), update.getExtGwMacAddress())) {
1123             handleRouterGwFlows(original, dpnId, NwConstants.DEL_FLOW);
1124             handleRouterGwFlows(update, dpnId, NwConstants.ADD_FLOW);
1125         }
1126
1127         //Check if the Update is on External IPs
1128         LOG.debug("NAT Service : Checking if this is update on External IPs");
1129         List<String> originalExternalIps = NatUtil.getIpsListFromExternalIps(original.getExternalIps());
1130         List<String> updatedExternalIps = NatUtil.getIpsListFromExternalIps(update.getExternalIps());
1131
1132         //Check if the External IPs are added during the update.
1133         Set<String> addedExternalIps = new HashSet<>(updatedExternalIps);
1134         addedExternalIps.removeAll(originalExternalIps);
1135         if (addedExternalIps.size() != 0) {
1136             LOG.debug("NAT Service : Start processing of the External IPs addition during the update operation");
1137             vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName, addedExternalIps,
1138                 update.getExtGwMacAddress(), dpnId,
1139                 update.getNetworkId(), null, NwConstants.ADD_FLOW);
1140
1141             for (String addedExternalIp : addedExternalIps) {
1142                 /*
1143                     1) Do nothing in the IntExtIp model.
1144                     2) Initialise the count of the added external IP to 0 in the ExternalCounter model.
1145                 */
1146                 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(addedExternalIp);
1147                 String externalIp = externalIpParts[0];
1148                 String externalIpPrefix = externalIpParts[1];
1149                 String externalpStr = externalIp + "/" + externalIpPrefix;
1150                 LOG.debug("NAT Service : Initialise the count mapping of the external IP {} for the "
1151                         + "router ID {} in the ExternalIpsCounter model.",
1152                     externalpStr, routerId);
1153                 naptManager.initialiseNewExternalIpCounter(routerId, externalpStr);
1154             }
1155             LOG.debug("NAT Service : End processing of the External IPs addition during the update operation");
1156         }
1157
1158         //Check if the External IPs are removed during the update.
1159         Set<String> removedExternalIps = new HashSet<>(originalExternalIps);
1160         removedExternalIps.removeAll(updatedExternalIps);
1161         if (removedExternalIps.size() > 0) {
1162             LOG.debug("NAT Service : Start processing of the External IPs removal during the update operation");
1163             vpnManager.setupArpResponderFlowsToExternalNetworkIps(routerName,
1164                 removedExternalIps, original.getExtGwMacAddress(),
1165                 dpnId, networkId, null, NwConstants.DEL_FLOW);
1166
1167             for (String removedExternalIp : removedExternalIps) {
1168              /*
1169                 1) Remove the mappings in the IntExt IP model which has external IP.
1170                 2) Remove the external IP in the ExternalCounter model.
1171                 3) For the corresponding subnet IDs whose external IP mapping was removed, allocate one of the least
1172                  loaded external IP.
1173                    Store the subnet IP and the reallocated external IP mapping in the IntExtIp model.
1174                 4) Increase the count of the allocated external IP by one.
1175                 5) Advertise to the BGP if external IP is allocated for the first time for the router
1176                  i.e. the route for the external IP is absent.
1177                 6) Remove the NAPT translation entries from Inbound and Outbound NAPT tables for
1178                  the removed external IPs and also from the model.
1179                 7) Advertise to the BGP for removing the route for the removed external IPs.
1180               */
1181
1182                 String[] externalIpParts = NatUtil.getExternalIpAndPrefix(removedExternalIp);
1183                 String externalIp = externalIpParts[0];
1184                 String externalIpPrefix = externalIpParts[1];
1185                 String externalIpAddrStr = externalIp + "/" + externalIpPrefix;
1186
1187                 LOG.debug("NAT Service : Clear the routes from the BGP and remove the FIB and TS "
1188                     + "entries for removed external IP {}", externalIpAddrStr);
1189                 Uuid vpnUuId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1190                 String vpnName = "";
1191                 if (vpnUuId != null) {
1192                     vpnName = vpnUuId.getValue();
1193                 }
1194                 clrRtsFromBgpAndDelFibTs(dpnId, routerId, externalIpAddrStr, vpnName);
1195
1196                 LOG.debug("NAT Service : Remove the mappings in the IntExtIP model which has external IP.");
1197                 //Get the internal IPs which are associated to the removed external IPs
1198                 List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1199                 List<String> removedInternalIps = new ArrayList<>();
1200                 for (IpMap ipMap : ipMaps) {
1201                     if (ipMap.getExternalIp().equals(externalIpAddrStr)) {
1202                         removedInternalIps.add(ipMap.getInternalIp());
1203                     }
1204                 }
1205
1206                 LOG.debug("Remove the mappings of the internal IPs from the IntExtIP model.");
1207                 for (String removedInternalIp : removedInternalIps) {
1208                     LOG.debug("NAT Service : Remove the IP mapping of the internal IP {} for the "
1209                             + "router ID {} from the IntExtIP model",
1210                         removedInternalIp, routerId);
1211                     naptManager.removeFromIpMapDS(routerId, removedInternalIp);
1212                 }
1213
1214                 LOG.debug("NAT Service : Remove the count mapping of the external IP {} for the "
1215                         + "router ID {} from the ExternalIpsCounter model.",
1216                     externalIpAddrStr, routerId);
1217                 naptManager.removeExternalIpCounter(routerId, externalIpAddrStr);
1218
1219                 LOG.debug("NAT Service : Allocate the least loaded external IPs to the subnets "
1220                     + "whose external IPs were removed.");
1221                 for (String removedInternalIp : removedInternalIps) {
1222                     allocateExternalIp(dpnId, update, routerId, routerName, networkId, removedInternalIp);
1223                 }
1224
1225                 LOG.debug("NAT Service : Remove the NAPT translation entries from "
1226                     + "Inbound and Outbound NAPT tables for the removed external IPs.");
1227                 //Get the internalIP and internal Port which were associated to the removed external IP.
1228                 List<Integer> externalPorts = new ArrayList<>();
1229                 Map<ProtocolTypes, List<String>> protoTypesIntIpPortsMap = new HashMap<>();
1230                 InstanceIdentifier<IpPortMapping> ipPortMappingId = InstanceIdentifier.builder(IntextIpPortMap.class)
1231                     .child(IpPortMapping.class, new IpPortMappingKey(routerId)).build();
1232                 Optional<IpPortMapping> ipPortMapping =
1233                     MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, ipPortMappingId);
1234                 if (ipPortMapping.isPresent()) {
1235                     List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.get().getIntextIpProtocolType();
1236                     for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1237                         ProtocolTypes protoType = intextIpProtocolType.getProtocol();
1238                         List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1239                         for (IpPortMap ipPortMap : ipPortMaps) {
1240                             IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1241                             if (ipPortExternal.getIpAddress().equals(externalIp)) {
1242                                 externalPorts.add(ipPortExternal.getPortNum());
1243                                 List<String> removedInternalIpPorts = protoTypesIntIpPortsMap.get(protoType);
1244                                 if (removedInternalIpPorts != null) {
1245                                     removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1246                                     protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1247                                 } else {
1248                                     removedInternalIpPorts = new ArrayList<>();
1249                                     removedInternalIpPorts.add(ipPortMap.getIpPortInternal());
1250                                     protoTypesIntIpPortsMap.put(protoType, removedInternalIpPorts);
1251                                 }
1252                             }
1253                         }
1254                     }
1255                 }
1256
1257                 //Remove the IP port map from the intext-ip-port-map model, which were containing
1258                 // the removed external IP.
1259                 Set<Map.Entry<ProtocolTypes, List<String>>> protoTypesIntIpPorts = protoTypesIntIpPortsMap.entrySet();
1260                 Map<String, List<String>> internalIpPortMap = new HashMap<>();
1261                 for (Map.Entry protoTypesIntIpPort : protoTypesIntIpPorts) {
1262                     ProtocolTypes protocolType = (ProtocolTypes) protoTypesIntIpPort.getKey();
1263                     List<String> removedInternalIpPorts = (List<String>) protoTypesIntIpPort.getValue();
1264                     for (String removedInternalIpPort : removedInternalIpPorts) {
1265                         // Remove the IP port map from the intext-ip-port-map model,
1266                         // which were containing the removed external IP
1267                         naptManager.removeFromIpPortMapDS(routerId, removedInternalIpPort, protocolType);
1268                         //Remove the IP port incomint packer map.
1269                         naptPacketInHandler.removeIncomingPacketMap(removedInternalIpPort);
1270                         String[] removedInternalIpPortParts = removedInternalIpPort.split(":");
1271                         if (removedInternalIpPortParts.length == 2) {
1272                             String removedInternalIp = removedInternalIpPortParts[0];
1273                             String removedInternalPort = removedInternalIpPortParts[1];
1274                             List<String> removedInternalPortsList = internalIpPortMap.get(removedInternalPort);
1275                             if (removedInternalPortsList != null) {
1276                                 removedInternalPortsList.add(removedInternalPort);
1277                                 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1278                             } else {
1279                                 removedInternalPortsList = new ArrayList<>();
1280                                 removedInternalPortsList.add(removedInternalPort);
1281                                 internalIpPortMap.put(removedInternalIp, removedInternalPortsList);
1282                             }
1283                         }
1284                     }
1285                 }
1286
1287                 // Delete the entry from SnatIntIpPortMap DS
1288                 Set<String> internalIps = internalIpPortMap.keySet();
1289                 for (String internalIp : internalIps) {
1290                     LOG.debug("NAT Service : Removing IpPort having the internal IP {} from the "
1291                         + "model SnatIntIpPortMap", internalIp);
1292                     naptManager.removeFromSnatIpPortDS(routerId, internalIp);
1293                 }
1294
1295                 naptManager.removeNaptPortPool(externalIp);
1296
1297                 LOG.debug("Remove the NAPT translation entries from Inbound NAPT tables for the removed "
1298                     + "external IP {}", externalIp);
1299                 for (Integer externalPort : externalPorts) {
1300                     //Remove the NAPT translation entries from Inbound NAPT table
1301                     naptEventHandler.removeNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1302                         routerId, externalIp, externalPort);
1303                 }
1304
1305                 Set<Map.Entry<String, List<String>>> internalIpPorts = internalIpPortMap.entrySet();
1306                 for (Map.Entry<String, List<String>> internalIpPort : internalIpPorts) {
1307                     String internalIp = internalIpPort.getKey();
1308                     LOG.debug("Remove the NAPT translation entries from Outbound NAPT tables for "
1309                         + "the removed internal IP {}", internalIp);
1310                     List<String> internalPorts = internalIpPort.getValue();
1311                     for (String internalPort : internalPorts) {
1312                         //Remove the NAPT translation entries from Outbound NAPT table
1313                         naptEventHandler.removeNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1314                             routerId, internalIp, Integer.valueOf(internalPort));
1315                     }
1316                 }
1317             }
1318             LOG.debug("NAT Service : End processing of the External IPs removal during the update operation");
1319         }
1320
1321         //Check if its Update on subnets
1322         LOG.debug("NAT Service : Checking if this is update on subnets");
1323         List<Uuid> originalSubnetIds = original.getSubnetIds();
1324         List<Uuid> updatedSubnetIds = update.getSubnetIds();
1325         Set<Uuid> addedSubnetIds = new HashSet<>(updatedSubnetIds);
1326         addedSubnetIds.removeAll(originalSubnetIds);
1327
1328         //Check if the Subnet IDs are added during the update.
1329         if (addedSubnetIds.size() != 0) {
1330             LOG.debug("NAT Service : Start processing of the Subnet IDs addition during the update operation");
1331             for (Uuid addedSubnetId : addedSubnetIds) {
1332                 /*
1333                   1) Select the least loaded external IP for the subnet and store the mapping of the
1334                   subnet IP and the external IP in the IntExtIp model.
1335                   2) Increase the count of the selected external IP by one.
1336                   3) Advertise to the BGP if external IP is allocated for the first time for the
1337                   router i.e. the route for the external IP is absent.
1338                 */
1339                 String subnetIp = NatUtil.getSubnetIp(dataBroker, addedSubnetId);
1340                 if (subnetIp != null) {
1341                     allocateExternalIp(dpnId, update, routerId, routerName, networkId, subnetIp);
1342                 }
1343             }
1344             LOG.debug("NAT Service : End processing of the Subnet IDs addition during the update operation");
1345         }
1346
1347         //Check if the Subnet IDs are removed during the update.
1348         Set<Uuid> removedSubnetIds = new HashSet<>(originalSubnetIds);
1349         removedSubnetIds.removeAll(updatedSubnetIds);
1350         if (removedSubnetIds.size() != 0) {
1351             LOG.debug("NAT Service : Start processing of the Subnet IDs removal during the update operation");
1352             for (Uuid removedSubnetId : removedSubnetIds) {
1353                 String[] subnetAddr = NatUtil.getSubnetIpAndPrefix(dataBroker, removedSubnetId);
1354                 if (subnetAddr != null) {
1355                     /*
1356                     1) Remove the subnet IP and the external IP in the IntExtIp map
1357                     2) Decrease the count of the coresponding external IP by one.
1358                     3) Advertise to the BGP for removing the routes of the corresponding external
1359                      IP if its not allocated to any other internal IP.
1360                     */
1361
1362                     String externalIp =
1363                         naptManager.getExternalIpAllocatedForSubnet(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1364                     if (externalIp == null) {
1365                         LOG.debug("No mapping found for router ID {} and internal IP {}", routerId, subnetAddr[0]);
1366                         return;
1367                     }
1368
1369                     naptManager.updateCounter(routerId, externalIp, false);
1370                     // Traverse entire model of external-ip counter whether external ip is not
1371                     // used by any other internal ip in any router
1372                     if (!isExternalIpAllocated(externalIp)) {
1373                         LOG.debug("NAT Service : external ip is not allocated to any other "
1374                             + "internal IP so proceeding to remove routes");
1375                         List<String> externalIps = new ArrayList<>();
1376                         externalIps.add(externalIp);
1377                         clrRtsFromBgpAndDelFibTs(dpnId, routerId, networkId, externalIps, null);
1378                         LOG.debug("Successfully removed fib entries in switch {} for "
1379                                 + "router {} with networkId {} and externalIps {}",
1380                             dpnId, routerId, networkId, externalIps);
1381                     }
1382
1383                     LOG.debug("NAT Service : Remove the IP mapping for the router ID {} and "
1384                         + "internal IP {} external IP {}", routerId, subnetAddr[0], externalIp);
1385                     naptManager.removeIntExtIpMapDS(routerId, subnetAddr[0] + "/" + subnetAddr[1]);
1386                 }
1387             }
1388             LOG.debug("NAT Service : End processing of the Subnet IDs removal during the update operation");
1389         }
1390     }
1391
1392     private boolean isExternalIpAllocated(String externalIp) {
1393         InstanceIdentifier<ExternalIpsCounter> id = InstanceIdentifier.builder(ExternalIpsCounter.class).build();
1394         Optional<ExternalIpsCounter> externalCountersData =
1395             MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
1396         if (externalCountersData.isPresent()) {
1397             ExternalIpsCounter externalIpsCounters = externalCountersData.get();
1398             List<ExternalCounters> externalCounters = externalIpsCounters.getExternalCounters();
1399             for (ExternalCounters ext : externalCounters) {
1400                 for (ExternalIpCounter externalIpCount : ext.getExternalIpCounter()) {
1401                     if (externalIpCount.getExternalIp().equals(externalIp)) {
1402                         if (externalIpCount.getCounter() != 0) {
1403                             return true;
1404                         }
1405                         break;
1406                     }
1407                 }
1408             }
1409         }
1410         return false;
1411     }
1412
1413     private void allocateExternalIp(BigInteger dpnId, Routers router, long routerId, String routerName,
1414             Uuid networkId, String subnetIp) {
1415         String[] subnetIpParts = NatUtil.getSubnetIpAndPrefix(subnetIp);
1416         try {
1417             InetAddress address = InetAddress.getByName(subnetIpParts[0]);
1418             if (address instanceof Inet6Address) {
1419                 // TODO: Revisit when IPv6 external connectivity support is added.
1420                 LOG.debug("Currently skipping ipv6 address {}.", address);
1421                 return;
1422             }
1423         } catch (UnknownHostException e) {
1424             LOG.warn("Invalid ip address {}", subnetIpParts[0], e);
1425             return;
1426         }
1427         String leastLoadedExtIpAddr = NatUtil.getLeastLoadedExternalIp(dataBroker, routerId);
1428         if (leastLoadedExtIpAddr != null) {
1429             String[] externalIpParts = NatUtil.getExternalIpAndPrefix(leastLoadedExtIpAddr);
1430             String leastLoadedExtIp = externalIpParts[0];
1431             String leastLoadedExtIpPrefix = externalIpParts[1];
1432             IPAddress externalIpAddr = new IPAddress(leastLoadedExtIp, Integer.parseInt(leastLoadedExtIpPrefix));
1433             subnetIp = subnetIpParts[0];
1434             String subnetIpPrefix = subnetIpParts[1];
1435             IPAddress subnetIpAddr = new IPAddress(subnetIp, Integer.parseInt(subnetIpPrefix));
1436             LOG.debug("NAT Service : Add the IP mapping for the router ID {} and internal "
1437                     + "IP {} and prefix {} -> external IP {} and prefix {}",
1438                 routerId, subnetIp, subnetIpPrefix, leastLoadedExtIp, leastLoadedExtIpPrefix);
1439             naptManager.registerMapping(routerId, subnetIpAddr, externalIpAddr);
1440
1441
1442             // Check if external IP is already assigned a route. (i.e. External IP is previously
1443             // allocated to any of the subnets)
1444             // If external IP is already assigned a route, (, do not re-advertise to the BGP
1445             String leastLoadedExtIpAddrStr = leastLoadedExtIp + "/" + leastLoadedExtIpPrefix;
1446             Long label = checkExternalIpLabel(routerId, leastLoadedExtIpAddrStr);
1447             if (label != null) {
1448                 //update
1449                 String internalIp = subnetIpParts[0] + "/" + subnetIpParts[1];
1450                 IpMapKey ipMapKey = new IpMapKey(internalIp);
1451                 LOG.debug("Setting label {} for internalIp {} and externalIp {}",
1452                     label, internalIp, leastLoadedExtIpAddrStr);
1453                 IpMap newIpm = new IpMapBuilder().setKey(ipMapKey).setInternalIp(internalIp)
1454                     .setExternalIp(leastLoadedExtIpAddrStr).setLabel(label).build();
1455                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL,
1456                     naptManager.getIpMapIdentifier(routerId, internalIp), newIpm);
1457                 return;
1458             }
1459
1460             // Re-advertise to the BGP for the external IP, which is allocated to the subnet
1461             // for the first time and hence not having a route.
1462             //Get the VPN Name using the network ID
1463             final String vpnName = NatUtil.getAssociatedVPN(dataBroker, networkId, LOG);
1464             if (vpnName != null) {
1465                 LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkId);
1466                 if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
1467                     LOG.debug("Best effort for getting primary napt switch when router i/f are"
1468                         + "added after gateway-set");
1469                     dpnId = NatUtil.getPrimaryNaptfromRouterId(dataBroker, routerId);
1470                 }
1471                 advToBgpAndInstallFibAndTsFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, vpnName, routerId, routerName,
1472                     leastLoadedExtIp + "/" + leastLoadedExtIpPrefix, router,
1473                     vpnService, fibService, bgpManager, dataBroker, LOG);
1474             }
1475         }
1476     }
1477
1478     protected Long checkExternalIpLabel(long routerId, String externalIp) {
1479         List<IpMap> ipMaps = naptManager.getIpMapList(dataBroker, routerId);
1480         for (IpMap ipMap : ipMaps) {
1481             if (ipMap.getExternalIp().equals(externalIp)) {
1482                 if (ipMap.getLabel() != null) {
1483                     return ipMap.getLabel();
1484                 }
1485             }
1486         }
1487         return null;
1488     }
1489
1490     @Override
1491     protected void remove(InstanceIdentifier<Routers> identifier, Routers router) {
1492         LOG.trace("NAT Service : Router delete method");
1493         {
1494         /*
1495             ROUTER DELETE SCENARIO
1496             1) Get the router ID from the event.
1497             2) Build the cookie information from the router ID.
1498             3) Get the primary and secondary switch DPN IDs using the router ID from the model.
1499             4) Build the flow with the cookie value.
1500             5) Delete the flows which matches the cookie information from the NAPT outbound, inbound tables.
1501             6) Remove the flows from the other switches which points to the primary and secondary
1502              switches for the flows related the router ID.
1503             7) Get the list of external IP address maintained for the router ID.
1504             8) Use the NaptMananager removeMapping API to remove the list of IP addresses maintained.
1505             9) Withdraw the corresponding routes from the BGP.
1506          */
1507
1508             if (identifier == null || router == null) {
1509                 LOG.info("++++++++++++++NAT Service : ExternalRoutersListener:remove:: "
1510                     + "returning without processing since routers is null");
1511                 return;
1512             }
1513
1514             String routerName = router.getRouterName();
1515             LOG.info("Removing default NAT route from FIB on all dpns part of router {} ", routerName);
1516             addOrDelDefFibRouteToSNAT(routerName, false);
1517             Uuid networkUuid = router.getNetworkId();
1518             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1519             if (routerId == NatConstants.INVALID_ID) {
1520                 LOG.error("NAT Service : Remove external router event - Invalid routerId for routerName {}",
1521                     routerName);
1522                 return;
1523             }
1524
1525             BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
1526             handleRouterGwFlows(router, primarySwitchId, NwConstants.DEL_FLOW);
1527             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
1528             handleDisableSnat(router, networkUuid, externalIps, true, null, primarySwitchId);
1529         }
1530     }
1531
1532     private void handleRouterGwFlows(Routers router, BigInteger primarySwitchId, int addOrRemove) {
1533         WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
1534         vpnManager.setupRouterGwMacFlow(router.getRouterName(), router.getExtGwMacAddress(), primarySwitchId,
1535             router.getNetworkId(), writeTx, addOrRemove);
1536         vpnManager.setupArpResponderFlowsToExternalNetworkIps(router.getRouterName(),
1537             NatUtil.getIpsListFromExternalIps(router.getExternalIps()),
1538             router.getExtGwMacAddress(), primarySwitchId, router.getNetworkId(), writeTx, addOrRemove);
1539         writeTx.submit();
1540     }
1541
1542     // TODO Clean up the exception handling
1543     @SuppressWarnings("checkstyle:IllegalCatch")
1544     public void handleDisableSnat(Routers router, Uuid networkUuid, List<String> externalIps, boolean routerFlag,
1545                                   String vpnId, BigInteger naptSwitchDpnId) {
1546         LOG.info("NAT Service : handleDisableSnat() Entry");
1547         String routerName = router.getRouterName();
1548         try {
1549             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1550             // Use the NaptMananager removeMapping API to remove the entire list of IP addresses maintained
1551             // for the router ID.
1552             LOG.debug("NAT Service : Remove the Internal to external IP address maintained for the "
1553                 + "router ID {} in the DS", routerId);
1554             naptManager.removeMapping(routerId);
1555
1556             if (routerFlag) {
1557                 removeNaptSwitch(routerName);
1558             } else {
1559                 updateNaptSwitch(routerName, BigInteger.ZERO);
1560             }
1561
1562             LOG.debug("NAT Service : Remove the ExternalCounter model for the router ID {}", routerId);
1563             naptManager.removeExternalCounter(routerId);
1564
1565             LOG.debug("NAT Service : got primarySwitch as dpnId {}", naptSwitchDpnId);
1566             if (naptSwitchDpnId == null || naptSwitchDpnId.equals(BigInteger.ZERO)) {
1567                 LOG.error("NAT Service : Unable to retrieve the primary NAPT switch for the "
1568                     + "router ID {} from RouterNaptSwitch model", routerId);
1569                 return;
1570             }
1571             removeNaptFlowsFromActiveSwitch(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId, externalIps);
1572             removeFlowsFromNonActiveSwitches(routerName, naptSwitchDpnId, networkUuid);
1573             try {
1574                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1575             } catch (Exception ex) {
1576                 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}",
1577                     routerId, naptSwitchDpnId, ex);
1578             }
1579
1580         } catch (Exception ex) {
1581             LOG.error("Exception while handling disableSNAT : {}", ex);
1582         }
1583         LOG.info("NAT Service : handleDisableSnat() Exit");
1584     }
1585
1586     // TODO Clean up the exception handling
1587     @SuppressWarnings("checkstyle:IllegalCatch")
1588     public void handleDisableSnatInternetVpn(String routerName, Uuid networkUuid, List<String> externalIps,
1589                                              boolean routerFlag, String vpnId) {
1590         LOG.debug("NAT Service : handleDisableSnatInternetVpn() Entry");
1591         try {
1592             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1593             BigInteger naptSwitchDpnId = null;
1594             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch =
1595                 NatUtil.buildNaptSwitchRouterIdentifier(routerName);
1596             Optional<RouterToNaptSwitch> rtrToNapt =
1597                 read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerToNaptSwitch);
1598             if (rtrToNapt.isPresent()) {
1599                 naptSwitchDpnId = rtrToNapt.get().getPrimarySwitchId();
1600             }
1601             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", naptSwitchDpnId);
1602
1603             removeNaptFlowsFromActiveSwitchInternetVpn(routerId, routerName, naptSwitchDpnId, networkUuid, vpnId);
1604             try {
1605                 clrRtsFromBgpAndDelFibTs(naptSwitchDpnId, routerId, networkUuid, externalIps, vpnId);
1606             } catch (Exception ex) {
1607                 LOG.debug("Failed to remove fib entries for routerId {} in naptSwitchDpnId {} : {}",
1608                     routerId, naptSwitchDpnId, ex);
1609             }
1610         } catch (Exception ex) {
1611             LOG.error("Exception while handling disableSNATInternetVpn : {}", ex);
1612         }
1613         LOG.debug("NAT Service : handleDisableSnatInternetVpn() Exit");
1614     }
1615
1616     // TODO Clean up the exception handling
1617     @SuppressWarnings("checkstyle:IllegalCatch")
1618     public void updateNaptSwitch(String routerName, BigInteger naptSwitchId) {
1619         RouterToNaptSwitch naptSwitch = new RouterToNaptSwitchBuilder().setKey(new RouterToNaptSwitchKey(routerName))
1620             .setPrimarySwitchId(naptSwitchId).build();
1621         try {
1622             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
1623                 NatUtil.buildNaptSwitchRouterIdentifier(routerName), naptSwitch);
1624         } catch (Exception ex) {
1625             LOG.error("Failed to write naptSwitch {} for router {} in ds",
1626                 naptSwitchId, routerName);
1627         }
1628         LOG.debug("Successfully updated naptSwitch {} for router {} in ds",
1629             naptSwitchId, routerName);
1630     }
1631
1632     protected void removeNaptSwitch(String routerName) {
1633         // Remove router and switch from model
1634         InstanceIdentifier<RouterToNaptSwitch> id =
1635             InstanceIdentifier.builder(NaptSwitches.class)
1636                 .child(RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
1637         LOG.debug("NAPT Service : Removing NaptSwitch and Router for the router {} from datastore", routerName);
1638         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
1639         //Release allocated router_lPort_tag from the ID Manager if Router is on L3VPNOverVxlan
1640         NatEvpnUtil.releaseLPortTagForRouter(dataBroker, idManager, routerName);
1641     }
1642
1643     public void removeNaptFlowsFromActiveSwitch(long routerId, String routerName,
1644                                                 BigInteger dpnId, Uuid networkId, String vpnName,
1645                                                 List<String> externalIps) {
1646         LOG.debug("NAT Service : Remove NAPT flows from Active switch");
1647         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1648
1649         //Remove the PSNAT entry which forwards the packet to Outbound NAPT Table (For the
1650         // traffic which comes from the  VMs of the NAPT switches)
1651         String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, routerName);
1652         FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1653
1654         LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1655             NwConstants.PSNAT_TABLE, dpnId, routerId);
1656         mdsalManager.removeFlow(preSnatFlowEntity);
1657
1658         //Remove the Terminating Service table entry which forwards the packet to Outbound NAPT Table (For the
1659         // traffic which comes from the VMs of the non NAPT switches)
1660         long tunnelId = NatEvpnUtil.getTunnelIdForRouter(idManager, dataBroker, routerName, routerId);
1661         String tsFlowRef = getFlowRefTs(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tunnelId);
1662         FlowEntity tsNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, tsFlowRef);
1663         LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1664             NwConstants.INTERNAL_TUNNEL_TABLE, dpnId, routerId);
1665         mdsalManager.removeFlow(tsNatFlowEntity);
1666
1667         //Remove the Outbound flow entry which forwards the packet to FIB Table
1668         String outboundNatFlowRef = getFlowRefOutbound(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
1669         FlowEntity outboundNatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1670             outboundNatFlowRef);
1671
1672         LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1673             NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1674         mdsalManager.removeFlow(outboundNatFlowEntity);
1675
1676         removeNaptFibExternalOutputFlows(routerId, dpnId, networkId, externalIps);
1677
1678         //Remove the NAPT PFIB TABLE which forwards the incoming packet to FIB Table matching on the router ID.
1679         String natPfibFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, routerId);
1680         FlowEntity natPfibFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibFlowRef);
1681
1682         LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and router ID {}",
1683             NwConstants.NAPT_PFIB_TABLE, dpnId, routerId);
1684         mdsalManager.removeFlow(natPfibFlowEntity);
1685
1686         // Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
1687         // - This does not work since ext-routers is deleted already - no network info
1688         //Get the VPN ID from the ExternalNetworks model
1689         long vpnId = -1;
1690         if ((vpnName == null) || (vpnName.isEmpty())) {
1691             // ie called from router delete cases
1692             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1693             LOG.debug("NAT Service : vpnUuid is {}", vpnUuid);
1694             if (vpnUuid != null) {
1695                 vpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1696                 LOG.debug("NAT Service : vpnId for routerdelete or disableSNAT scenario {}", vpnId);
1697             }
1698         } else {
1699             // ie called from disassociate vpn case
1700             LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1701             vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1702             LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId);
1703         }
1704
1705         if (vpnId != NatConstants.INVALID_ID) {
1706             //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1707             String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1708             FlowEntity natPfibVpnFlowEntity =
1709                 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1710             LOG.info("NAT Service : Remove the flow in the for the active switch with the DPN ID {} and VPN ID {}",
1711                 NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1712             mdsalManager.removeFlow(natPfibVpnFlowEntity);
1713         }
1714
1715         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
1716         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1717         if (ipPortMapping == null) {
1718             LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1719             return;
1720         }
1721
1722         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1723         for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1724             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1725             for (IpPortMap ipPortMap : ipPortMaps) {
1726                 String ipPortInternal = ipPortMap.getIpPortInternal();
1727                 String[] ipPortParts = ipPortInternal.split(":");
1728                 if (ipPortParts.length != 2) {
1729                     LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1730                     return;
1731                 }
1732                 String internalIp = ipPortParts[0];
1733                 String internalPort = ipPortParts[1];
1734
1735                 //Build the flow for the outbound NAPT table
1736                 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1737                     String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1738                 FlowEntity outboundNaptFlowEntity =
1739                     NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1740
1741                 LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} and "
1742                     + "router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1743                 mdsalManager.removeFlow(outboundNaptFlowEntity);
1744
1745                 IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1746                 String externalIp = ipPortExternal.getIpAddress();
1747                 int externalPort = ipPortExternal.getPortNum();
1748
1749                 //Build the flow for the inbound NAPT table
1750                 switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1751                     String.valueOf(routerId), externalIp, externalPort);
1752                 FlowEntity inboundNaptFlowEntity =
1753                     NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1754
1755                 LOG.info("NAT Service : Remove the flow in the {} for the active active switch with the "
1756                     + "DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
1757                 mdsalManager.removeFlow(inboundNaptFlowEntity);
1758             }
1759         }
1760     }
1761
1762     protected void removeNaptFibExternalOutputFlows(long routerId, BigInteger dpnId, Uuid networkId,
1763                                                     List<String> externalIps) {
1764         Long extVpnId = null;
1765         if (networkId != null) {
1766             Uuid vpnUuid = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
1767             if (vpnUuid != null) {
1768                 extVpnId = NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
1769             } else {
1770                 LOG.debug("NAT Service: removeNaptFibExternalOutputFlows - vpnUuid is null");
1771             }
1772         } else {
1773             LOG.debug("NAT Service: removeNaptFibExternalOutputFlows - networkId is null");
1774             extVpnId = NatUtil.getVpnId(dataBroker, routerId);
1775         }
1776         if (extVpnId == null || extVpnId == NatConstants.INVALID_ID) {
1777             LOG.debug("removeNaptFibExternalOutputFlows - extVpnId not found for routerId {}", routerId);
1778             extVpnId = routerId;
1779         }
1780         for (String ip : externalIps) {
1781             String extIp = removeMaskFromIp(ip);
1782             String naptFlowRef = getFlowRefNaptFib(dpnId, NwConstants.NAPT_PFIB_TABLE, extVpnId, extIp);
1783             LOG.info("NAT Service: Remove the flow in the " + NwConstants.NAPT_PFIB_TABLE + " for the active switch"
1784                 + " with the DPN ID {} and router ID {} and IP {} flowRef {}", dpnId, routerId, extIp, naptFlowRef);
1785             mdsalManager.removeFlow(NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, naptFlowRef));
1786         }
1787     }
1788
1789     private String removeMaskFromIp(String ip) {
1790         if (ip != null && !ip.trim().isEmpty()) {
1791             return ip.split("/")[0];
1792         }
1793         return ip;
1794     }
1795
1796     public void removeNaptFlowsFromActiveSwitchInternetVpn(long routerId, String routerName,
1797                                                            BigInteger dpnId, Uuid networkId, String vpnName) {
1798         LOG.debug("NAT Service : Remove NAPT flows from Active switch Internet Vpn");
1799         BigInteger cookieSnatFlow = NatUtil.getCookieNaptFlow(routerId);
1800
1801         //Remove the NAPT PFIB TABLE entry
1802         long vpnId = -1;
1803         if (vpnName != null) {
1804             // ie called from disassociate vpn case
1805             LOG.debug("NAT Service: This is disassociate nw with vpn case with vpnName {}", vpnName);
1806             vpnId = NatUtil.getVpnId(dataBroker, vpnName);
1807             LOG.debug("NAT Service : vpnId for disassociate nw with vpn scenario {}", vpnId);
1808         }
1809
1810         if (vpnId != NatConstants.INVALID_ID) {
1811             //Remove the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
1812             String natPfibVpnFlowRef = getFlowRefTs(dpnId, NwConstants.NAPT_PFIB_TABLE, vpnId);
1813             FlowEntity natPfibVpnFlowEntity =
1814                 NatUtil.buildFlowEntity(dpnId, NwConstants.NAPT_PFIB_TABLE, natPfibVpnFlowRef);
1815             LOG.info("NAT Service : Remove the flow in the {} for the active switch with the DPN ID {} "
1816                 + "and VPN ID {}", NwConstants.NAPT_PFIB_TABLE, dpnId, vpnId);
1817             mdsalManager.removeFlow(natPfibVpnFlowEntity);
1818
1819             // Remove IP-PORT active NAPT entries and release port from IdManager
1820             // For the router ID get the internal IP , internal port and the corresponding
1821             // external IP and external Port.
1822             IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
1823             if (ipPortMapping == null) {
1824                 LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
1825                 return;
1826             }
1827             List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
1828             for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
1829                 List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
1830                 for (IpPortMap ipPortMap : ipPortMaps) {
1831                     String ipPortInternal = ipPortMap.getIpPortInternal();
1832                     String[] ipPortParts = ipPortInternal.split(":");
1833                     if (ipPortParts.length != 2) {
1834                         LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
1835                         return;
1836                     }
1837                     String internalIp = ipPortParts[0];
1838                     String internalPort = ipPortParts[1];
1839
1840                     //Build the flow for the outbound NAPT table
1841                     String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.OUTBOUND_NAPT_TABLE,
1842                         String.valueOf(routerId), internalIp, Integer.valueOf(internalPort));
1843                     FlowEntity outboundNaptFlowEntity =
1844                         NatUtil.buildFlowEntity(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1845
1846                     LOG.info("NAT Service : Remove the flow in the {} for the active switch with the "
1847                         + "DPN ID {} and router ID {}", NwConstants.OUTBOUND_NAPT_TABLE, dpnId, routerId);
1848                     mdsalManager.removeFlow(outboundNaptFlowEntity);
1849
1850                     IpPortExternal ipPortExternal = ipPortMap.getIpPortExternal();
1851                     String externalIp = ipPortExternal.getIpAddress();
1852                     int externalPort = ipPortExternal.getPortNum();
1853
1854                     //Build the flow for the inbound NAPT table
1855                     switchFlowRef = NatUtil.getNaptFlowRef(dpnId, NwConstants.INBOUND_NAPT_TABLE,
1856                         String.valueOf(routerId), externalIp, externalPort);
1857                     FlowEntity inboundNaptFlowEntity =
1858                         NatUtil.buildFlowEntity(dpnId, NwConstants.INBOUND_NAPT_TABLE, cookieSnatFlow, switchFlowRef);
1859
1860                     LOG.info("NAT Service : Remove the flow in the {} for the active active switch with "
1861                         + "the DPN ID {} and router ID {}", NwConstants.INBOUND_NAPT_TABLE, dpnId, routerId);
1862                     mdsalManager.removeFlow(inboundNaptFlowEntity);
1863
1864                     // Finally release port from idmanager
1865                     String internalIpPort = internalIp + ":" + internalPort;
1866                     naptManager.removePortFromPool(internalIpPort, externalIp);
1867
1868                     //Remove sessions from models
1869                     naptManager.removeIpPortMappingForRouterID(routerId);
1870                     naptManager.removeIntIpPortMappingForRouterID(routerId);
1871                 }
1872             }
1873         } else {
1874             LOG.error("NAT Service : Invalid vpnId {}", vpnId);
1875         }
1876     }
1877
1878     public void removeFlowsFromNonActiveSwitches(String routerName, BigInteger naptSwitchDpnId, Uuid networkId) {
1879         LOG.debug("NAT Service : Remove NAPT related flows from non active switches");
1880
1881         // Remove the flows from the other switches which points to the primary and secondary switches
1882         // for the flows related the router ID.
1883         List<BigInteger> allSwitchList = naptSwitchSelector.getDpnsForVpn(routerName);
1884         if (allSwitchList == null || allSwitchList.isEmpty()) {
1885             LOG.error("NAT Service : Unable to get the swithces for the router {}", routerName);
1886             return;
1887         }
1888         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
1889         for (BigInteger dpnId : allSwitchList) {
1890             if (!naptSwitchDpnId.equals(dpnId)) {
1891                 LOG.info("NAT Service : Handle Ordinary switch");
1892
1893                 //Remove the PSNAT entry which forwards the packet to Terminating Service table
1894                 String preSnatFlowRef = getFlowRefSnat(dpnId, NwConstants.PSNAT_TABLE, String.valueOf(routerName));
1895                 FlowEntity preSnatFlowEntity = NatUtil.buildFlowEntity(dpnId, NwConstants.PSNAT_TABLE, preSnatFlowRef);
1896
1897                 LOG.info("Remove the flow in the {} for the non active switch with the DPN ID {} and router ID {}",
1898                     NwConstants.PSNAT_TABLE, dpnId, routerId);
1899                 mdsalManager.removeFlow(preSnatFlowEntity);
1900
1901                 //Remove the group entry which forwards the traffic to the out port (VXLAN tunnel).
1902                 long groupId = createGroupId(getGroupIdKey(routerName));
1903                 List<BucketInfo> listBucketInfo = new ArrayList<>();
1904                 GroupEntity preSnatGroupEntity =
1905                     MDSALUtil.buildGroupEntity(dpnId, groupId, routerName, GroupTypes.GroupAll, listBucketInfo);
1906
1907                 LOG.info("NAT Service : Remove the group {} for the non active switch with the DPN ID {} "
1908                     + "and router ID {}", groupId, dpnId, routerId);
1909                 mdsalManager.removeGroup(preSnatGroupEntity);
1910
1911             }
1912         }
1913     }
1914
1915     public void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, Long routerId, Uuid networkUuid,
1916                                          List<String> externalIps, String vpnName) {
1917         //Withdraw the corresponding routes from the BGP.
1918         //Get the network ID using the router ID.
1919         LOG.debug("NAT Service : Advertise to BGP and remove routes for externalIps {} with routerId {},"
1920                 + "network Id {} and vpnName {}",
1921             externalIps, routerId, networkUuid, vpnName);
1922         if (networkUuid == null) {
1923             LOG.error("NAT Service : networkId is null");
1924             return;
1925         }
1926
1927         if (externalIps == null || externalIps.isEmpty()) {
1928             LOG.debug("NAT Service : externalIps is null");
1929             return;
1930         }
1931
1932         if (vpnName == null) {
1933             //Get the VPN Name using the network ID
1934             vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
1935             if (vpnName == null) {
1936                 LOG.error("No VPN associated with ext nw {} for the router {}",
1937                     networkUuid, routerId);
1938                 return;
1939             }
1940         }
1941         LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
1942
1943         //Remove custom FIB routes
1944         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
1945         for (String extIp : externalIps) {
1946             clrRtsFromBgpAndDelFibTs(dpnId, routerId, extIp, vpnName);
1947         }
1948     }
1949
1950     protected void clrRtsFromBgpAndDelFibTs(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
1951         clearBgpRoutes(extIp, vpnName);
1952         delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
1953     }
1954
1955     protected void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp,
1956                                              final String vpnName, long tempLabel) {
1957         LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
1958         String routerName = NatUtil.getRouterName(dataBroker,routerId);
1959         if (routerName == null) {
1960             LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
1961             return;
1962         }
1963         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
1964         if (extNwProvType == null) {
1965             return;
1966         }
1967         /*  Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
1968          * external network provided type is VxLAN
1969          */
1970         if (extNwProvType == ProviderTypes.VXLAN) {
1971             evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
1972             return;
1973         }
1974         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
1975             LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
1976             return;
1977         }
1978
1979         final long label = tempLabel;
1980         final String externalIp = extIp;
1981
1982         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
1983             .setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
1984         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
1985
1986         ListenableFuture<RpcResult<Void>> labelFuture =
1987             Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
1988                 (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
1989                     //Release label
1990                     if (result.isSuccessful()) {
1991                         removeTunnelTableEntry(dpnId, label);
1992                         removeLFibTableEntry(dpnId, label);
1993                         RemoveVpnLabelInput labelInput =
1994                             new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
1995                         Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
1996                         return JdkFutureAdapters.listenInPoolThread(labelFuture1);
1997                     } else {
1998                         String errMsg =
1999                             String.format("RPC call to remove custom FIB entries on dpn %s for prefix %s "
2000                                     + "Failed - %s", dpnId, externalIp, result.getErrors());
2001                         LOG.error(errMsg);
2002                         return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2003                     }
2004                 });
2005
2006         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
2007
2008             @Override
2009             public void onFailure(Throwable error) {
2010                 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
2011             }
2012
2013             @Override
2014             public void onSuccess(RpcResult<Void> result) {
2015                 if (result.isSuccessful()) {
2016                     LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}",
2017                         externalIp, vpnName);
2018                 } else {
2019                     LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}",
2020                         externalIp, vpnName, result.getErrors());
2021                 }
2022             }
2023         });
2024     }
2025
2026     private void delFibTsAndReverseTraffic(final BigInteger dpnId, long routerId, String extIp, final String vpnName) {
2027         LOG.debug("NAT Service : Removing fib entry for externalIp {} in routerId {}", extIp, routerId);
2028         String routerName = NatUtil.getRouterName(dataBroker,routerId);
2029         if (routerName == null) {
2030             LOG.error("NAT Service : Could not retrieve Router Name from Router ID {} ", routerId);
2031             return;
2032         }
2033         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,routerName);
2034         if (extNwProvType == null) {
2035             return;
2036         }
2037         /* Remove the flow table19->44 and table36->44 entries for SNAT reverse traffic flow if the
2038          *  external network provided type is VxLAN
2039          */
2040         if (extNwProvType == ProviderTypes.VXLAN) {
2041             evpnSnatFlowProgrammer.evpnDelFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2042             return;
2043         }
2044         //Get IPMaps from the DB for the router ID
2045         List<IpMap> dbIpMaps = NaptManager.getIpMapList(dataBroker, routerId);
2046         if (dbIpMaps == null || dbIpMaps.isEmpty()) {
2047             LOG.error("NAT Service : IPMaps not found for router {}", routerId);
2048             return;
2049         }
2050
2051         long tempLabel = NatConstants.INVALID_ID;
2052         for (IpMap dbIpMap : dbIpMaps) {
2053             String dbExternalIp = dbIpMap.getExternalIp();
2054             LOG.debug("Retrieved dbExternalIp {} for router id {}", dbExternalIp, routerId);
2055             //Select the IPMap, whose external IP is the IP for which FIB is installed
2056             if (extIp.equals(dbExternalIp)) {
2057                 tempLabel = dbIpMap.getLabel();
2058                 LOG.debug("Retrieved label {} for dbExternalIp {} with router id {}",
2059                     tempLabel, dbExternalIp, routerId);
2060                 break;
2061             }
2062         }
2063         if (tempLabel < 0 || tempLabel == NatConstants.INVALID_ID) {
2064             LOG.error("NAT Service : Label not found for externalIp {} with router id {}", extIp, routerId);
2065             return;
2066         }
2067
2068         final long label = tempLabel;
2069         final String externalIp = extIp;
2070
2071         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder()
2072             .setVpnName(vpnName).setSourceDpid(dpnId).setIpAddress(externalIp).setServiceId(label).build();
2073         Future<RpcResult<Void>> future = fibService.removeFibEntry(input);
2074
2075         ListenableFuture<RpcResult<Void>> labelFuture =
2076             Futures.transform(JdkFutureAdapters.listenInPoolThread(future),
2077                 (AsyncFunction<RpcResult<Void>, RpcResult<Void>>) result -> {
2078                     //Release label
2079                     if (result.isSuccessful()) {
2080                         removeTunnelTableEntry(dpnId, label);
2081                         removeLFibTableEntry(dpnId, label);
2082                         RemoveVpnLabelInput labelInput =
2083                             new RemoveVpnLabelInputBuilder().setVpnName(vpnName).setIpPrefix(externalIp).build();
2084                         Future<RpcResult<Void>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
2085                         return JdkFutureAdapters.listenInPoolThread(labelFuture1);
2086                     } else {
2087                         String errMsg =
2088                             String.format("RPC call to remove custom FIB entries on dpn %s for "
2089                                 + "prefix %s Failed - %s",
2090                                 dpnId, externalIp, result.getErrors());
2091                         LOG.error(errMsg);
2092                         return Futures.immediateFailedFuture(new RuntimeException(errMsg));
2093                     }
2094                 });
2095
2096         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<Void>>() {
2097
2098             @Override
2099             public void onFailure(Throwable error) {
2100                 LOG.error("NAT Service : Error in removing the label or custom fib entries", error);
2101             }
2102
2103             @Override
2104             public void onSuccess(RpcResult<Void> result) {
2105                 if (result.isSuccessful()) {
2106                     LOG.debug("NAT Service : Successfully removed the label for the prefix {} from VPN {}",
2107                         externalIp, vpnName);
2108                 } else {
2109                     LOG.error("NAT Service : Error in removing the label for prefix {} from VPN {}, {}",
2110                         externalIp, vpnName, result.getErrors());
2111                 }
2112             }
2113         });
2114     }
2115
2116     protected void clearFibTsAndReverseTraffic(final BigInteger dpnId, Long routerId, Uuid networkUuid,
2117                                                List<String> externalIps, String vpnName) {
2118         //Withdraw the corresponding routes from the BGP.
2119         //Get the network ID using the router ID.
2120         LOG.debug("NAT Service : clearFibTsAndReverseTraffic for externalIps {} with routerId {},"
2121                 + "network Id {} and vpnName {}",
2122             externalIps, routerId, networkUuid, vpnName);
2123         if (networkUuid == null) {
2124             LOG.error("NAT Service : networkId is null");
2125             return;
2126         }
2127
2128         if (externalIps == null || externalIps.isEmpty()) {
2129             LOG.debug("NAT Service : externalIps is null");
2130             return;
2131         }
2132
2133         if (vpnName == null) {
2134             //Get the VPN Name using the network ID
2135             vpnName = NatUtil.getAssociatedVPN(dataBroker, networkUuid, LOG);
2136             if (vpnName == null) {
2137                 LOG.error("No VPN associated with ext nw {} for the router {}",
2138                     networkUuid, routerId);
2139                 return;
2140             }
2141         }
2142         LOG.debug("Retrieved vpnName {} for networkId {}", vpnName, networkUuid);
2143
2144         //Remove custom FIB routes
2145         //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
2146         for (String extIp : externalIps) {
2147             delFibTsAndReverseTraffic(dpnId, routerId, extIp, vpnName);
2148         }
2149     }
2150
2151     protected void clearBgpRoutes(String externalIp, final String vpnName) {
2152         //Inform BGP about the route removal
2153         LOG.info("Informing BGP to remove route for externalIP {} of vpn {}", externalIp, vpnName);
2154         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
2155         NatUtil.removePrefixFromBGP(dataBroker, bgpManager, fibManager, rd, externalIp, vpnName, LOG);
2156     }
2157
2158     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId) {
2159         LOG.info("NAT Service : remove terminatingServiceActions called with DpnId = {} and label = {}",
2160             dpnId, serviceId);
2161         List<MatchInfo> mkMatches = new ArrayList<>();
2162         // Matching metadata
2163         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
2164         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
2165             getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""),
2166             5, String.format("%s:%d", "TST Flow Entry ", serviceId), 0, 0,
2167             COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, null);
2168         mdsalManager.removeFlow(dpnId, flowEntity);
2169         LOG.debug("NAT Service : Terminating service Entry for dpID {} : label : {} removed successfully {}",
2170             dpnId, serviceId);
2171     }
2172
2173     private void removeLFibTableEntry(BigInteger dpnId, long serviceId) {
2174         List<MatchInfo> matches = new ArrayList<>();
2175         matches.add(MatchEthernetType.MPLS_UNICAST);
2176         matches.add(new MatchMplsLabel(serviceId));
2177
2178         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
2179
2180         LOG.debug("NAT Service : removing LFib entry with flow ref {}", flowRef);
2181
2182         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
2183             10, flowRef, 0, 0,
2184             COOKIE_VM_LFIB_TABLE, matches, null);
2185
2186         mdsalManager.removeFlow(dpnId, flowEntity);
2187
2188         LOG.debug("NAT Service : LFIB Entry for dpID : {} label : {} removed successfully {}", dpnId, serviceId);
2189     }
2190
2191     /**
2192      * router association to vpn.
2193      *
2194      * @param routerName - Name of router
2195      * @param bgpVpnName BGP VPN name
2196      */
2197     public void changeLocalVpnIdToBgpVpnId(String routerName, String bgpVpnName) {
2198         LOG.debug("NAT Service : Router associated to BGP VPN");
2199         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2200             long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2201
2202             LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2203
2204             if (bgpVpnId != NatConstants.INVALID_ID) {
2205                 LOG.debug("Populate the router-id-name container with the mapping BGP VPN-ID {} -> BGP VPN-NAME {}",
2206                     bgpVpnId, bgpVpnName);
2207                 RouterIds rtrs = new RouterIdsBuilder().setKey(new RouterIdsKey(bgpVpnId))
2208                     .setRouterId(bgpVpnId).setRouterName(bgpVpnName).build();
2209                 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
2210                     getRoutersIdentifier(bgpVpnId), rtrs);
2211
2212                 // Get the allocated Primary NAPT Switch for this router
2213                 long routerId = NatUtil.getVpnId(dataBroker, routerName);
2214                 LOG.debug("Router ID value {} ", routerId);
2215                 BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2216
2217                 LOG.debug("NAT Service : Update the Router ID {} to the BGP VPN ID {} ", routerId, bgpVpnId);
2218                 addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, bgpVpnId, true);
2219
2220                 // Get the group ID
2221                 long groupId = createGroupId(getGroupIdKey(routerName));
2222                 installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, true);
2223             }
2224         }
2225     }
2226
2227     /**
2228      * router disassociation from vpn.
2229      *
2230      * @param routerName - Name of router
2231      * @param bgpVpnName BGP VPN name
2232      */
2233     public void changeBgpVpnIdToLocalVpnId(String routerName, String bgpVpnName) {
2234         LOG.debug("NAT Service : Router dissociated from BGP VPN");
2235         if (chkExtRtrAndSnatEnbl(new Uuid(routerName))) {
2236             long bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnName);
2237             LOG.debug("BGP VPN ID value {} ", bgpVpnId);
2238
2239             // Get the allocated Primary NAPT Switch for this router
2240             long routerId = NatUtil.getVpnId(dataBroker, routerName);
2241             LOG.debug("Router ID value {} ", routerId);
2242             BigInteger primarySwitchId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
2243
2244             LOG.debug("NAT Service : Update the BGP VPN ID {} to the Router ID {}", bgpVpnId, routerId);
2245             addOrDelDefaultFibRouteForSnatWithBgpVpn(routerName, NatConstants.INVALID_ID, true);
2246
2247             // Get the group ID
2248             long groupId = createGroupId(getGroupIdKey(routerName));
2249             installFlowsWithUpdatedVpnId(primarySwitchId, routerName, NatConstants.INVALID_ID, routerId, true);
2250         }
2251     }
2252
2253     boolean chkExtRtrAndSnatEnbl(Uuid routerUuid) {
2254         InstanceIdentifier<Routers> routerInstanceIndentifier =
2255             InstanceIdentifier.builder(ExtRouters.class)
2256                 .child(Routers.class, new RoutersKey(routerUuid.getValue())).build();
2257         Optional<Routers> routerData = read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerInstanceIndentifier);
2258         return routerData.isPresent() && routerData.get().isEnableSnat();
2259     }
2260
2261     public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2262                                              long routerId, boolean isSnatCfgd) {
2263         installFlowsWithUpdatedVpnId(primarySwitchId, routerName, bgpVpnId, routerId, isSnatCfgd, null);
2264     }
2265
2266     public void installFlowsWithUpdatedVpnId(BigInteger primarySwitchId, String routerName, long bgpVpnId,
2267                                              long routerId, boolean isSnatCfgd, Routers router) {
2268         long changedVpnId = bgpVpnId;
2269         String logMsg = "NAT Service : Update the BGP VPN ID {}";
2270         if (bgpVpnId == NatConstants.INVALID_ID) {
2271             changedVpnId = routerId;
2272             logMsg = "NAT Service : Update the router ID {}";
2273         }
2274
2275         List<BigInteger> switches = NatUtil.getDpnsForRouter(dataBroker, routerName);
2276         if (switches == null || switches.isEmpty()) {
2277             LOG.debug("No switches found for router {}", routerName);
2278             return;
2279         }
2280         for (BigInteger dpnId : switches) {
2281             // Update the BGP VPN ID in the SNAT miss entry to group
2282             if (!dpnId.equals(primarySwitchId)) {
2283                 LOG.debug("NAT Service : Install group in non NAPT switch {}", dpnId);
2284                 List<BucketInfo> bucketInfoForNonNaptSwitches =
2285                     getBucketInfoForNonNaptSwitches(dpnId, primarySwitchId, routerName);
2286                 long groupId = createGroupId(getGroupIdKey(routerName));
2287                 if (!isSnatCfgd) {
2288                     groupId = installGroup(dpnId, routerName, bucketInfoForNonNaptSwitches);
2289                 }
2290
2291                 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the non NAPT switch {}",
2292                     changedVpnId, groupId, dpnId);
2293                 FlowEntity flowEntity = buildSnatFlowEntityWithUpdatedVpnId(dpnId, routerName, groupId, changedVpnId);
2294                 mdsalManager.installFlow(flowEntity);
2295             } else {
2296                 LOG.debug(logMsg + " in the SNAT miss entry pointing to group {} in the primary switch {}",
2297                     changedVpnId, primarySwitchId);
2298                 FlowEntity flowEntity =
2299                     buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(primarySwitchId, routerName, changedVpnId);
2300                 mdsalManager.installFlow(flowEntity);
2301
2302                 LOG.debug(logMsg + " in the Terminating Service table (table ID 36) which forwards the packet"
2303                     + " to the table 46 in the Primary switch {}", changedVpnId, primarySwitchId);
2304                 installTerminatingServiceTblEntryWithUpdatedVpnId(primarySwitchId, routerName, changedVpnId);
2305
2306                 LOG.debug(logMsg + " in the Outbound NAPT table (table ID 46) which punts the packet to the"
2307                     + " controller in the Primary switch {}", changedVpnId, primarySwitchId);
2308                 createOutboundTblEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2309
2310                 LOG.debug(logMsg + " in the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table in the"
2311                         + "Primary switch {}",
2312                     changedVpnId, primarySwitchId);
2313                 installNaptPfibEntryWithBgpVpn(primarySwitchId, routerId, changedVpnId);
2314
2315                 LOG.debug(logMsg + " in the NAPT flows for the Outbound NAPT table (table ID 46) and the "
2316                         + "INBOUND NAPT table (table ID 44) in the Primary switch {}",
2317                     changedVpnId, primarySwitchId);
2318                 updateNaptFlowsWithVpnId(primarySwitchId, routerId, bgpVpnId);
2319
2320                 LOG.debug("NAT Service : Installing SNAT PFIB flow in the primary switch {}", primarySwitchId);
2321                 Long vpnId = NatUtil.getVpnId(dataBroker, routerId);
2322                 //Install the NAPT PFIB TABLE which forwards the outgoing packet to FIB Table matching on the VPN ID.
2323                 if (vpnId != null && vpnId != NatConstants.INVALID_ID) {
2324                     installNaptPfibEntry(primarySwitchId, vpnId);
2325                 }
2326             }
2327         }
2328     }
2329
2330     public void updateNaptFlowsWithVpnId(BigInteger dpnId, long routerId, long bgpVpnId) {
2331         //For the router ID get the internal IP , internal port and the corresponding external IP and external Port.
2332         IpPortMapping ipPortMapping = NatUtil.getIportMapping(dataBroker, routerId);
2333         if (ipPortMapping == null) {
2334             LOG.error("NAT Service : Unable to retrieve the IpPortMapping");
2335             return;
2336         }
2337         // Get the External Gateway MAC Address
2338         String extGwMacAddress = NatUtil.getExtGwMacAddFromRouterId(dataBroker, routerId);
2339         if (extGwMacAddress != null) {
2340             LOG.debug("External Gateway MAC address {} found for External Router ID {}", extGwMacAddress, routerId);
2341         } else {
2342             LOG.error("No External Gateway MAC address found for External Router ID {}", routerId);
2343             return;
2344         }
2345         List<IntextIpProtocolType> intextIpProtocolTypes = ipPortMapping.getIntextIpProtocolType();
2346         for (IntextIpProtocolType intextIpProtocolType : intextIpProtocolTypes) {
2347             List<IpPortMap> ipPortMaps = intextIpProtocolType.getIpPortMap();
2348             for (IpPortMap ipPortMap : ipPortMaps) {
2349                 String ipPortInternal = ipPortMap.getIpPortInternal();
2350                 String[] ipPortParts = ipPortInternal.split(":");
2351                 if (ipPortParts.length != 2) {
2352                     LOG.error("NAT Service : Unable to retrieve the Internal IP and port");
2353                     return;
2354                 }
2355                 String internalIp = ipPortParts[0];
2356                 String internalPort = ipPortParts[1];
2357                 LOG.debug("NAT Service : Found Internal IP {} and Internal Port {}", internalIp, internalPort);
2358                 ProtocolTypes protocolTypes = intextIpProtocolType.getProtocol();
2359                 NAPTEntryEvent.Protocol protocol;
2360                 switch (protocolTypes) {
2361                     case TCP:
2362                         protocol = NAPTEntryEvent.Protocol.TCP;
2363                         break;
2364                     case UDP:
2365                         protocol = NAPTEntryEvent.Protocol.UDP;
2366                         break;
2367                     default:
2368                         protocol = NAPTEntryEvent.Protocol.TCP;
2369                 }
2370                 SessionAddress internalAddress = new SessionAddress(internalIp, Integer.valueOf(internalPort));
2371                 SessionAddress externalAddress =
2372                         naptManager.getExternalAddressMapping(routerId, internalAddress, protocol);
2373                 long internetVpnid = NatUtil.getVpnId(dataBroker, routerId);
2374                 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.INBOUND_NAPT_TABLE, internetVpnid,
2375                         routerId, bgpVpnId, externalAddress, internalAddress, protocol, extGwMacAddress);
2376                 NaptEventHandler.buildAndInstallNatFlows(dpnId, NwConstants.OUTBOUND_NAPT_TABLE, internetVpnid,
2377                         routerId, bgpVpnId, internalAddress, externalAddress, protocol, extGwMacAddress);
2378             }
2379         }
2380     }
2381
2382     public FlowEntity buildSnatFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long groupId,
2383                                                           long changedVpnId) {
2384
2385         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} groupId {} "
2386             + "changed VPN ID {}", dpId, routerName, groupId, changedVpnId);
2387         List<MatchInfo> matches = new ArrayList<>();
2388         matches.add(MatchEthernetType.IPV4);
2389         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2390
2391         List<ActionInfo> actionsInfo = new ArrayList<>();
2392         actionsInfo.add(new ActionSetFieldTunnelId(BigInteger.valueOf(changedVpnId)));
2393         LOG.debug("NAT Service : Setting the tunnel to the list of action infos {}", actionsInfo);
2394         actionsInfo.add(new ActionGroup(groupId));
2395         List<InstructionInfo> instructions = new ArrayList<>();
2396         instructions.add(new InstructionApplyActions(actionsInfo));
2397         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2398         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2399             NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2400             NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2401
2402         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2403         return flowEntity;
2404     }
2405
2406     public FlowEntity buildSnatFlowEntityWithUpdatedVpnIdForPrimrySwtch(BigInteger dpId, String routerName,
2407                                                                         long changedVpnId) {
2408
2409         LOG.debug("NAT Service : buildSnatFlowEntity is called for dpId {}, routerName {} changed VPN ID {}",
2410             dpId, routerName, changedVpnId);
2411         List<MatchInfo> matches = new ArrayList<>();
2412         matches.add(MatchEthernetType.IPV4);
2413         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2414
2415         List<InstructionInfo> instructions = new ArrayList<>();
2416         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2417
2418         String flowRef = getFlowRefSnat(dpId, NwConstants.PSNAT_TABLE, routerName);
2419         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
2420             NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2421             NwConstants.COOKIE_SNAT_TABLE, matches, instructions);
2422
2423         LOG.debug("NAT Service : Returning SNAT Flow Entity {}", flowEntity);
2424         return flowEntity;
2425     }
2426
2427     // TODO : Replace this with ITM Rpc once its available with full functionality
2428     protected void installTerminatingServiceTblEntryWithUpdatedVpnId(BigInteger dpnId, String routerName,
2429                                                                      long changedVpnId) {
2430         LOG.debug("NAT Service : installTerminatingServiceTblEntryWithUpdatedVpnId called for switch {}, "
2431             + "routerName {}, BGP VPN ID {}", dpnId, routerName, changedVpnId);
2432         FlowEntity flowEntity = buildTsFlowEntityWithUpdatedVpnId(dpnId, routerName, changedVpnId);
2433         mdsalManager.installFlow(flowEntity);
2434
2435     }
2436
2437     private FlowEntity buildTsFlowEntityWithUpdatedVpnId(BigInteger dpId, String routerName, long changedVpnId) {
2438         LOG.debug("NAT Service : buildTsFlowEntityWithUpdatedVpnId called for switch {}, routerName {}, BGP VPN ID {}",
2439             dpId, routerName, changedVpnId);
2440         BigInteger bgpVpnIdAsBigInt = BigInteger.valueOf(changedVpnId);
2441         List<MatchInfo> matches = new ArrayList<>();
2442         matches.add(MatchEthernetType.IPV4);
2443         matches.add(new MatchTunnelId(bgpVpnIdAsBigInt));
2444
2445         List<InstructionInfo> instructions = new ArrayList<>();
2446         instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2447             MetaDataUtil.METADATA_MASK_VRFID));
2448         instructions.add(new InstructionGotoTable(NwConstants.OUTBOUND_NAPT_TABLE));
2449         BigInteger routerId = BigInteger.valueOf(NatUtil.getVpnId(dataBroker, routerName));
2450         String flowRef = getFlowRefTs(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, routerId.longValue());
2451         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INTERNAL_TUNNEL_TABLE, flowRef,
2452             NatConstants.DEFAULT_TS_FLOW_PRIORITY, flowRef, 0, 0,
2453             NwConstants.COOKIE_TS_TABLE, matches, instructions);
2454         return flowEntity;
2455     }
2456
2457     public void createOutboundTblEntryWithBgpVpn(BigInteger dpnId, long routerId, long changedVpnId) {
2458         LOG.debug("NAT Service : createOutboundTblEntry called for dpId {} and routerId {}, BGP VPN ID {}",
2459             dpnId, routerId, changedVpnId);
2460         FlowEntity flowEntity = buildOutboundFlowEntityWithBgpVpn(dpnId, routerId, changedVpnId);
2461         LOG.debug("NAT Service : Installing flow {}", flowEntity);
2462         mdsalManager.installFlow(flowEntity);
2463     }
2464
2465     protected FlowEntity buildOutboundFlowEntityWithBgpVpn(BigInteger dpId, long routerId, long changedVpnId) {
2466         LOG.debug("NAT Service : buildOutboundFlowEntityWithBgpVpn called for dpId {} and routerId {}, BGP VPN ID {}",
2467             dpId, routerId, changedVpnId);
2468         List<MatchInfo> matches = new ArrayList<>();
2469         matches.add(MatchEthernetType.IPV4);
2470         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2471
2472         List<InstructionInfo> instructions = new ArrayList<>();
2473         List<ActionInfo> actionsInfos = new ArrayList<>();
2474         actionsInfos.add(new ActionPuntToController());
2475         instructions.add(new InstructionApplyActions(actionsInfos));
2476         instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId),
2477             MetaDataUtil.METADATA_MASK_VRFID));
2478
2479         String flowRef = getFlowRefOutbound(dpId, NwConstants.OUTBOUND_NAPT_TABLE, routerId);
2480         BigInteger cookie = getCookieOutboundFlow(routerId);
2481         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.OUTBOUND_NAPT_TABLE,
2482             flowRef, 5, flowRef, 0, 0, cookie, matches, instructions);
2483         LOG.debug("NAT Service : returning flowEntity {}", flowEntity);
2484         return flowEntity;
2485     }
2486
2487     public void installNaptPfibEntryWithBgpVpn(BigInteger dpnId, long segmentId, long changedVpnId) {
2488         LOG.debug("NAT Service : installNaptPfibEntryWithBgpVpn called for dpnId {} and segmentId {} ,BGP VPN ID {}",
2489             dpnId, segmentId, changedVpnId);
2490         FlowEntity naptPfibFlowEntity = buildNaptPfibFlowEntityWithUpdatedVpnId(dpnId, segmentId, changedVpnId);
2491         mdsalManager.installFlow(naptPfibFlowEntity);
2492     }
2493
2494     public FlowEntity buildNaptPfibFlowEntityWithUpdatedVpnId(BigInteger dpId, long segmentId, long changedVpnId) {
2495
2496         LOG.debug("NAT Service : buildNaptPfibFlowEntityWithUpdatedVpnId is called for dpId {}, "
2497             + "segmentId {}, BGP VPN ID {}", dpId, segmentId, changedVpnId);
2498         List<MatchInfo> matches = new ArrayList<>();
2499         matches.add(MatchEthernetType.IPV4);
2500         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(changedVpnId), MetaDataUtil.METADATA_MASK_VRFID));
2501
2502         ArrayList<ActionInfo> listActionInfo = new ArrayList<>();
2503         ArrayList<InstructionInfo> instructionInfo = new ArrayList<>();
2504         listActionInfo.add(new ActionNxLoadInPort(BigInteger.ZERO));
2505         listActionInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
2506         instructionInfo.add(new InstructionApplyActions(listActionInfo));
2507
2508         String flowRef = getFlowRefTs(dpId, NwConstants.NAPT_PFIB_TABLE, segmentId);
2509         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.NAPT_PFIB_TABLE, flowRef,
2510             NatConstants.DEFAULT_PSNAT_FLOW_PRIORITY, flowRef, 0, 0,
2511             NwConstants.COOKIE_SNAT_TABLE, matches, instructionInfo);
2512         LOG.debug("NAT Service : Returning NaptPFib Flow Entity {}", flowEntity);
2513         return flowEntity;
2514     }
2515
2516     @Override
2517     protected ExternalRoutersListener getDataTreeChangeListener() {
2518         return ExternalRoutersListener.this;
2519     }
2520
2521     protected void installNaptPfibEntriesForExternalSubnets(String routerName, BigInteger dpnId) {
2522         List<Uuid> externalSubnetIdsForRouter = NatUtil.getExternalSubnetIdsForRouter(dataBroker,
2523                 routerName);
2524         for (Uuid externalSubnetId : externalSubnetIdsForRouter) {
2525             long subnetVpnId = NatUtil.getVpnId(dataBroker, externalSubnetId.getValue());
2526             if (subnetVpnId != -1) {
2527                 LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for dpnId {} "
2528                     + "and vpnId {}", dpnId, subnetVpnId);
2529                 installNaptPfibEntry(dpnId, subnetVpnId);
2530             }
2531         }
2532     }
2533 }