MRI version bumpup for Aluminium
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatTepChangeListener.java
1 /*
2  * Copyright (c) 2019 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 static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import javax.annotation.PreDestroy;
22 import javax.inject.Inject;
23 import javax.inject.Singleton;
24 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
25 import org.opendaylight.genius.infra.Datastore.Configuration;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
28 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
29 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
30 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
31 import org.opendaylight.infrautils.utils.concurrent.Executors;
32 import org.opendaylight.mdsal.binding.api.DataBroker;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
35 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
36 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
37 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnEndpoints;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.DpnRoutersList;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.dpn.routers.dpn.routers.list.RoutersList;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.RpcResult;
61 import org.opendaylight.yangtools.yang.common.Uint32;
62 import org.opendaylight.yangtools.yang.common.Uint64;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66 @Singleton
67 public class NatTepChangeListener extends AbstractAsyncDataTreeChangeListener<TunnelEndPoints> {
68
69     private static final Logger LOG = LoggerFactory
70         .getLogger(NatTepChangeListener.class);
71     private final DataBroker dataBroker;
72     private SNATDefaultRouteProgrammer defaultRouteProgrammer;
73     private OdlInterfaceRpcService interfaceService;
74     private IdManagerService idManager;
75     private IFibManager fibManager;
76     private IBgpManager bgpManager;
77     private IMdsalApiManager mdsalManager;
78     private FloatingIPListener floatingIPListener;
79     private FibRpcService fibRpcService;
80     private NaptSwitchHA naptSwitchHA;
81     private final NatMode natMode;
82     private final SnatServiceManager natServiceManager;
83     private final JobCoordinator coordinator;
84     private final ManagedNewTransactionRunner txRunner;
85     private final NatOverVxlanUtil natOverVxlanUtil;
86
87     @Inject
88     public NatTepChangeListener(final DataBroker dataBroker,
89         final SNATDefaultRouteProgrammer defaultRouteProgrammer,
90         final OdlInterfaceRpcService interfaceService,
91         final IdManagerService idManager, final IFibManager fibManager,
92         final IBgpManager bgpManager,
93         final FloatingIPListener floatingIPListener,
94         final FibRpcService fibRpcService,
95         final IMdsalApiManager mdsalManager,
96         final NaptSwitchHA naptSwitchHA,
97         final NatserviceConfig config,
98         final SnatServiceManager natServiceManager,
99         final JobCoordinator coordinator,
100         final NatOverVxlanUtil natOverVxlanUtil) {
101         super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.builder(DpnEndpoints.class)
102                 .child(DPNTEPsInfo.class).child(TunnelEndPoints.class).build(),
103                 Executors.newListeningSingleThreadExecutor("NatTepChangeListener", LOG));
104         this.dataBroker = dataBroker;
105         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
106         this.defaultRouteProgrammer = defaultRouteProgrammer;
107         this.interfaceService = interfaceService;
108         this.idManager = idManager;
109         this.fibManager = fibManager;
110         this.bgpManager = bgpManager;
111         this.floatingIPListener = floatingIPListener;
112         this.fibRpcService = fibRpcService;
113         this.naptSwitchHA = naptSwitchHA;
114         this.mdsalManager = mdsalManager;
115         this.coordinator = coordinator;
116         this.natServiceManager = natServiceManager;
117         this.natOverVxlanUtil = natOverVxlanUtil;
118         if (config != null) {
119             this.natMode = config.getNatMode();
120         } else {
121             this.natMode = NatMode.Controller;
122         }
123     }
124
125     public void init() {
126         LOG.info("{} init", getClass().getSimpleName());
127     }
128
129     @Override
130     @PreDestroy
131     public void close() {
132         super.close();
133         Executors.shutdownAndAwaitTermination(getExecutorService());
134     }
135
136     @Override
137     public void remove(InstanceIdentifier<TunnelEndPoints> key,
138         TunnelEndPoints tep) {
139         /*
140          * Whenever the TEP on a given DPNID is removed, this API take care
141          * of withdrawing the FIB entries for those Floating-IP existing on this
142          * DPN and perform re-election of NAPT Switch for a VRF to which the current
143          * DPN is elected as NAPT Switch.
144          */
145         Uint64 srcDpnId = key.firstIdentifierOf(DPNTEPsInfo.class)
146             .firstKeyOf(DPNTEPsInfo.class).getDPNID();
147         final String srcTepIp = tep.getIpAddress().stringValue();
148         String tunnelType = tep.getTunnelType().getName();
149         LOG.debug(
150             "NAT Service : Remove Event triggered for Tep on DPN:{} having IP:{} and tunnelType:{}",
151             srcDpnId, srcTepIp, tunnelType);
152         handleTepDelForAllRtrs(srcDpnId, srcTepIp);
153     }
154
155     @Override
156     public void update(InstanceIdentifier<TunnelEndPoints> key,
157         TunnelEndPoints origTep, TunnelEndPoints updatedTep) {
158         // Will be handled in NatTunnelInterfaceStateListener.add()
159         LOG.debug("NO ACTION duing update event : {}", updatedTep.key());
160     }
161
162     @Override
163     public void add(InstanceIdentifier<TunnelEndPoints> key,
164         TunnelEndPoints tep) {
165         LOG.debug("NO ACTION duing add event : {}", tep.key());
166     }
167
168     @SuppressWarnings("checkstyle:IllegalCatch")
169     private void handleTepDelForAllRtrs(Uint64 srcDpnId, String srcTepIp) {
170         LOG.trace("handleTepDelForAllRtrs : TEP DEL ----- on DPN-ID {} having SRC IP : {}",
171             srcDpnId,
172             srcTepIp);
173
174         List<RoutersList> routersList = null;
175         InstanceIdentifier<DpnRoutersList> dpnRoutersListId = NatUtil.getDpnRoutersId(srcDpnId);
176         Optional<DpnRoutersList> optionalRouterDpnList =
177             SingleTransactionDataBroker
178                 .syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
179                     LogicalDatastoreType.OPERATIONAL, dpnRoutersListId);
180         if (optionalRouterDpnList.isPresent()) {
181             routersList = new ArrayList<RoutersList>(optionalRouterDpnList.get().getRoutersList().values());
182         } else {
183             LOG.debug(
184                 "NAT Service : RouterDpnList is empty for DPN {}. Hence ignoring TEP DEL event",
185                 srcDpnId);
186             return;
187         }
188
189         if (routersList == null) {
190             LOG.error("handleTepDelForAllRtrs : DPN {} does not have the Routers presence",
191                 srcDpnId);
192             return;
193         }
194
195         for (RoutersList router : routersList) {
196             String routerName = router.getRouter();
197             LOG.debug(
198                 "handleTepDelForAllRtrs :  TEP DEL : DNAT -> Withdrawing routes for router {} ",
199                 routerName);
200             Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
201             if (routerId == NatConstants.INVALID_ID) {
202                 LOG.error("handleTepDelForAllRtrs :Invalid ROUTER-ID {} returned for routerName {}",
203                     routerId, routerName);
204                 return;
205             }
206             Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker, routerName);
207             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
208                 routerName, externalNetworkId);
209             if (extNwProvType == null) {
210                 return;
211             }
212             boolean isFipExists = hndlTepDelForDnatInEachRtr(router, routerId, srcDpnId,
213                 extNwProvType);
214             LOG.debug(
215                 "handleTepDelForAllRtrs :  TEP DEL : SNAT -> Withdrawing and Advertising routes for router {} ",
216                 router.getRouter());
217             coordinator.enqueueJob((NatConstants.NAT_DJC_PREFIX + router.getRouter()), () -> {
218                 List<ListenableFuture<Void>> futures = new ArrayList<>();
219                 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, configTx -> {
220                     hndlTepDelForSnatInEachRtr(router, routerId, srcDpnId, srcTepIp, isFipExists,
221                         extNwProvType, configTx);
222                 });
223
224                 return futures;
225             }, NatConstants.NAT_DJC_MAX_RETRIES);
226         }
227         return;
228     }
229
230     private boolean hndlTepDelForDnatInEachRtr(RoutersList router, Uint32 routerId,
231         Uint64 tepDeletedDpnId,
232         ProviderTypes extNwProvType) {
233         //DNAT : Withdraw the routes from the BGP
234         String routerName = router.getRouter();
235         Boolean isFipExists = Boolean.FALSE;
236
237         LOG.debug("hndlTepDelForDnatInEachRtr : DNAT -> Trying to clear routes to the Floating IP "
238             + "associated to the router {}", routerName);
239
240         InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerName);
241         Optional<RouterPorts> optRouterPorts;
242         try {
243             optRouterPorts = SingleTransactionDataBroker.syncReadOptional(dataBroker,
244                     LogicalDatastoreType.CONFIGURATION, routerPortsId);
245         } catch (ExecutionException | InterruptedException e) {
246             LOG.error("hndlTepDelForDnatInEachRtr: Exception while reading RouterPorts DS for the router {}",
247                     routerName, e);
248             return isFipExists;
249         }
250         if (!optRouterPorts.isPresent()) {
251             LOG.debug(
252                 "hndlTepDelForDnatInEachRtr : DNAT -> Could not read Router Ports data object with id: {} "
253                     + "from DNAT FloatingIpInfo", routerName);
254             return isFipExists;
255         }
256         RouterPorts routerPorts = optRouterPorts.get();
257         Uuid extNwId = routerPorts.getExternalNetworkId();
258         final String vpnName = NatUtil.getAssociatedVPN(dataBroker, extNwId);
259         if (vpnName == null) {
260             LOG.error(
261                 "hndlTepDelForDnatInEachRtr : DNAT -> No External VPN associated with Ext N/W {} for Router {}",
262                 extNwId, routerName);
263             return isFipExists;
264         }
265         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
266         if (extNwProvType == null) {
267             return isFipExists;
268         }
269         Uint32 l3Vni = Uint32.ZERO;
270         if (extNwProvType == ProviderTypes.VXLAN) {
271             //get l3Vni value for external VPN
272             l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
273             if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
274                 LOG.debug(
275                     "hndlTepDelForDnatInEachRtr : L3VNI value is not configured in Internet VPN {} and RD {} "
276                         + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue to installing "
277                         + "NAT flows", vpnName, rd);
278                 l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId);
279             }
280         }
281         Map<PortsKey, Ports> interfacesMap = routerPorts.getPorts();
282         for (Ports port : interfacesMap.values()) {
283             //Get the DPN on which this interface resides
284             String interfaceName = port.getPortName();
285             Uint64 fipCfgdDpnId = NatUtil.getDpnForInterface(interfaceService, interfaceName);
286             if (fipCfgdDpnId.equals(Uint64.ZERO)) {
287                 LOG.info(
288                     "hndlTepDelForDnatInEachRtr : DNAT -> Abort processing Floating ip configuration. "
289                         + "No DPN for port : {}", interfaceName);
290                 continue;
291             }
292             if (!fipCfgdDpnId.equals(tepDeletedDpnId)) {
293                 LOG.info(
294                     "hndlTepDelForDnatInEachRtr : DNAT -> TEP deleted DPN {} is not the DPN {} which has the "
295                         + "floating IP configured for the port: {}",
296                     tepDeletedDpnId, fipCfgdDpnId, interfaceName);
297                 continue;
298             }
299             isFipExists = Boolean.TRUE;
300             Map<InternalToExternalPortMapKey, InternalToExternalPortMap> keyInternalToExternalPortMapMap
301                     = port.getInternalToExternalPortMap();
302             for (InternalToExternalPortMap intExtPortMap : keyInternalToExternalPortMapMap.values()) {
303                 String internalIp = intExtPortMap.getInternalIp();
304                 String externalIp = intExtPortMap.getExternalIp();
305                 externalIp = NatUtil.validateAndAddNetworkMask(externalIp);
306                 LOG.debug(
307                     "hndlTepDelForDnatInEachRtr : DNAT -> Withdrawing the FIB route to the floating IP {} "
308                         + "configured for the port: {}",
309                     externalIp, interfaceName);
310                 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, externalIp, vpnName);
311                 Uint32 serviceId = null;
312                 if (extNwProvType == ProviderTypes.VXLAN) {
313                     serviceId = l3Vni;
314                 } else {
315                     serviceId = floatingIPListener
316                         .getOperationalIpMapping(routerName, interfaceName, internalIp);
317                     if (serviceId == null || serviceId == NatConstants.INVALID_ID) {
318                         LOG.error(
319                             "hndlTepDelForDnatInEachRtr : DNAT -> Unable to remove the table 21 entry pushing the"
320                                 + " MPLS label to the tunnel since label is invalid");
321                         continue;
322                     }
323                 }
324
325                 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
326                     .setSourceDpid(fipCfgdDpnId).setIpAddress(externalIp).setServiceId(serviceId)
327                     .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
328                 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibRpcService
329                     .removeFibEntry(input);
330
331                 Futures.addCallback(future, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
332
333                     @Override
334                     public void onFailure(Throwable error) {
335                         LOG.error(
336                             "hndlTepDelForDnatInEachRtr : DNAT -> Error in removing the table 21 entry pushing "
337                                 + "the MPLS label to the tunnel since label is invalid ", error);
338                     }
339
340                     @Override
341                     public void onSuccess(RpcResult<RemoveFibEntryOutput> result) {
342                         if (result.isSuccessful()) {
343                             LOG.info(
344                                 "hndlTepDelForDnatInEachRtr : DNAT -> Successfully removed the entry pushing the "
345                                     + "MPLS label to the tunnel");
346                         } else {
347                             LOG.error(
348                                 "hndlTepDelForDnatInEachRtr : DNAT -> Error in fib rpc call to remove the table "
349                                     + "21 entry pushing the MPLS label to the tunnnel due to {}",
350                                 result.getErrors());
351                         }
352                     }
353                 }, MoreExecutors.directExecutor());
354             }
355         }
356         return isFipExists;
357     }
358
359     private void hndlTepDelForSnatInEachRtr(RoutersList router, Uint32 routerId, Uint64 dpnId,
360         String srcTepIp, Boolean isFipExists, ProviderTypes extNwProvType,
361         TypedReadWriteTransaction<Configuration> confTx)
362         throws ExecutionException, InterruptedException {
363
364         /*SNAT :
365         1) Elect a new switch as the primary NAPT
366         2) Advertise the new routes to BGP for the newly elected TEP IP as the DPN IP
367         3) This will make sure old routes are withdrawn and new routes are advertised.
368          */
369
370         String routerName = router.getRouter();
371         LOG.debug(
372             "hndlTepDelForSnatInEachRtr : SNAT -> Trying to clear routes to the External fixed IP associated "
373                 + "to the router {}", routerName);
374
375         // Check if this is externalRouter else ignore
376         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
377         Optional<Routers> routerData = Optional.empty();
378         try {
379             routerData = confTx.read(extRoutersId).get();
380         } catch (InterruptedException | ExecutionException e) {
381             LOG.error("Error retrieving routers {}", extRoutersId, e);
382         }
383         if (!routerData.isPresent()) {
384             LOG.debug(
385                 "hndlTepDelForSnatInEachRtr : SNAT->Ignoring TEP del for router {} since its not External Router",
386                 routerName);
387             return;
388         }
389
390         //Check if the DPN having the router is the NAPT switch
391         Uint64 naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
392         if (naptId == null || naptId.equals(Uint64.ZERO) || !naptId.equals(dpnId)) {
393             LOG.error(
394                 "hndlTepDelForSnatInEachRtr : SNAT -> Ignoring TEP delete for the DPN {} since"
395                     + "srcTepIp : {} is NOT a NAPT switch", dpnId, srcTepIp);
396             return;
397         }
398         if (natMode == NatMode.Conntrack) {
399             Routers extRouter = routerData.get();
400             natServiceManager.notify(confTx, extRouter, null, naptId, dpnId,
401                 SnatServiceManager.Action.CNT_ROUTER_DISBL);
402             if (extRouter.isEnableSnat()) {
403                 natServiceManager.notify(confTx, extRouter, null, naptId, dpnId,
404                     SnatServiceManager.Action.SNAT_ROUTER_DISBL);
405             }
406         } else {
407
408             Uuid networkId = routerData.get().getNetworkId();
409             if (networkId == null) {
410                 LOG.error(
411                     "hndlTepDelForSnatInEachRtr : SNAT -> Ignoring TEP delete for the DPN {} for router {}"
412                         + "as external network configuraton is missing", dpnId, routerName);
413                 return;
414             }
415
416             LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}",
417                 routerId, networkId);
418             Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
419             Uint32 bgpVpnId;
420             if (bgpVpnUuid == null) {
421                 LOG.debug(
422                     "hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
423                     routerId, routerName);
424                 bgpVpnId = routerId;
425             } else {
426                 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
427                 if (bgpVpnId == NatConstants.INVALID_ID) {
428                     LOG.error(
429                         "hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
430                         routerName);
431                     return;
432                 }
433             }
434             if (!isFipExists) {
435                 // Remove default entry in FIB to SNAT table
436                 LOG.debug(
437                     "NAT Service : Installing default route in FIB on DPN {} for router {} with"
438                         + " vpn {}...",
439                     dpnId, routerName, bgpVpnId);
440                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, bgpVpnId, routerId, confTx);
441             }
442
443             if (routerData.get().isEnableSnat()) {
444                 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
445
446                 Uint32 routerVpnId = routerId;
447                 if (bgpVpnId != NatConstants.INVALID_ID) {
448                     LOG.debug(
449                         "hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
450                             + "associated to the router {}", bgpVpnId, routerName);
451                     routerVpnId = bgpVpnId;
452                 } else {
453                     LOG.debug(
454                         "hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
455                             + "associated to the router {}", routerVpnId, routerName);
456                 }
457                 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
458                 String externalVpnName = NatUtil.getAssociatedVPN(dataBroker,
459                         routerData.get().getNetworkId());
460                 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, dpnId,
461                         routerData.get(), routerId, routerVpnId, externalVpnName, extNwProvType, confTx);
462             } else {
463                 LOG.info(
464                     "hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
465                     routerId, dpnId);
466             }
467         }
468     }
469 }