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