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