Ensure External Connectivity for NAPT Switch
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / FloatingIPListener.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.base.Optional;
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import javax.annotation.PostConstruct;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.infra.Datastore.Configuration;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.InstructionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfo;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
45 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
46 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
47 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
49 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
50 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
51 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
52 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
53 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
72
73 @Singleton
74 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
75     private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
76     private final DataBroker dataBroker;
77     private final ManagedNewTransactionRunner txRunner;
78     private final IMdsalApiManager mdsalManager;
79     private final OdlInterfaceRpcService interfaceManager;
80     private final FloatingIPHandler floatingIPHandler;
81     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
82     private final JobCoordinator coordinator;
83     private final CentralizedSwitchScheduler centralizedSwitchScheduler;
84
85     @Inject
86     public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
87                               final OdlInterfaceRpcService interfaceManager,
88                               final FloatingIPHandler floatingIPHandler,
89                               final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
90                               final JobCoordinator coordinator,
91                               final CentralizedSwitchScheduler centralizedSwitchScheduler) {
92         super(InternalToExternalPortMap.class, FloatingIPListener.class);
93         this.dataBroker = dataBroker;
94         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
95         this.mdsalManager = mdsalManager;
96         this.interfaceManager = interfaceManager;
97         this.floatingIPHandler = floatingIPHandler;
98         this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
99         this.coordinator = coordinator;
100         this.centralizedSwitchScheduler = centralizedSwitchScheduler;
101     }
102
103     @Override
104     @PostConstruct
105     public void init() {
106         LOG.info("{} init", getClass().getSimpleName());
107         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
108     }
109
110     @Override
111     protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
112         return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
113                 .child(InternalToExternalPortMap.class);
114     }
115
116     @Override
117     protected FloatingIPListener getDataTreeChangeListener() {
118         return FloatingIPListener.this;
119     }
120
121     @Override
122     protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
123                        final InternalToExternalPortMap mapping) {
124         LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.key(), mapping);
125         processFloatingIPAdd(identifier, mapping);
126     }
127
128     @Override
129     protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
130         LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.key(), mapping);
131         processFloatingIPDel(identifier, mapping);
132     }
133
134     @Override
135     protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
136             original, InternalToExternalPortMap update) {
137         LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
138                 update.key(), original, update);
139     }
140
141     private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
142             associatedVpn) {
143         String externalIp = mapping.getExternalIp();
144         Uuid floatingIpId = mapping.getExternalId();
145         //Get the FIP MAC address for DNAT
146         String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
147         if (floatingIpPortMacAddress == null) {
148             LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
149                     + "for floating IP {}", floatingIpId, externalIp);
150             return null;
151         }
152         LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
153         long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
154         LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
155
156         List<MatchInfo> matches = new ArrayList<>();
157         matches.add(MatchEthernetType.IPV4);
158
159         matches.add(new MatchIpv4Destination(externalIp, "32"));
160         //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
161         matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
162
163 //        matches.add(new MatchMetadata(
164 //                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
165         List<ActionInfo> actionsInfos = new ArrayList<>();
166         String internalIp = mapping.getInternalIp();
167         actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
168
169         List<InstructionInfo> instructions = new ArrayList<>();
170         instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
171                 MetaDataUtil.METADATA_MASK_VRFID));
172         instructions.add(new InstructionApplyActions(actionsInfos));
173         instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
174
175         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
176
177         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
178                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
179                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
180
181         return flowEntity;
182     }
183
184     private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
185             associatedVpn) {
186         String externalIp = mapping.getExternalIp();
187         LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
188
189         long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
190         LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
191
192         List<MatchInfo> matches = new ArrayList<>();
193         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
194
195         matches.add(MatchEthernetType.IPV4);
196         String internalIp = mapping.getInternalIp();
197         matches.add(new MatchIpv4Destination(internalIp, "32"));
198
199         List<ActionInfo> actionsInfos = new ArrayList<>();
200 //        actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
201
202         List<InstructionInfo> instructions = new ArrayList<>();
203 //        instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
204 //                (routerId), MetaDataUtil.METADATA_MASK_VRFID));
205         actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
206         instructions.add(new InstructionApplyActions(actionsInfos));
207         //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
208
209         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
210
211         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
212                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
213                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
214
215         return flowEntity;
216
217     }
218
219     private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
220             routerId, long associatedVpn) {
221
222         LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
223
224         long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
225
226         LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
227
228         List<MatchInfo> matches = new ArrayList<>();
229         matches.add(MatchEthernetType.IPV4);
230
231         matches.add(new MatchIpv4Source(internalIp, "32"));
232
233         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
234
235         List<ActionInfo> actionsInfos = new ArrayList<>();
236         actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
237
238         List<InstructionInfo> instructions = new ArrayList<>();
239         instructions.add(
240                 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
241         instructions.add(new InstructionApplyActions(actionsInfos));
242         instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
243
244         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
245
246         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
247                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
248                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
249
250         return flowEntity;
251     }
252
253     private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
254             externalNetworkId) {
255         String internalIp = mapping.getInternalIp();
256         LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
257
258         ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
259         if (provType == null) {
260             LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
261             return null;
262         }
263
264         List<MatchInfo> matches = new ArrayList<>();
265         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
266         matches.add(MatchEthernetType.IPV4);
267         String externalIp = mapping.getExternalIp();
268         matches.add(new MatchIpv4Source(externalIp, "32"));
269
270         List<ActionInfo> actionsInfo = new ArrayList<>();
271         Uuid floatingIpId = mapping.getExternalId();
272         String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
273         if (macAddress != null) {
274             actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
275         } else {
276             LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
277         }
278
279         LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
280         actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
281         List<InstructionInfo> instructions = new ArrayList<>();
282         instructions.add(new InstructionApplyActions(actionsInfo));
283         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
284
285         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
286                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
287                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
288
289         return flowEntity;
290
291     }
292
293     private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
294                                     long associatedVpnId, TypedReadWriteTransaction<Configuration> confTx) {
295         FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
296         if (preFlowEntity == null) {
297             LOG.error("createDNATTblEntry : Flow entity received as NULL. "
298                     + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
299                     NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
300         } else {
301             mdsalManager.addFlow(confTx, preFlowEntity);
302             FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
303             if (flowEntity != null) {
304                 mdsalManager.addFlow(confTx, flowEntity);
305             }
306         }
307     }
308
309     private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
310             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
311         FlowEntity preFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, externalIp, routerId);
312         mdsalManager.removeFlow(confTx, preFlowEntity);
313
314         FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, routerId);
315         if (flowEntity != null) {
316             mdsalManager.removeFlow(confTx, flowEntity);
317         }
318     }
319
320     private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
321         long associatedVpnId, Uuid externalNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
322         FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
323             vpnId, routerId, associatedVpnId);
324         mdsalManager.addFlow(confTx, preFlowEntity);
325
326         FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
327         if (flowEntity != null) {
328             mdsalManager.addFlow(confTx, flowEntity);
329         }
330     }
331
332     private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
333                                     TypedReadWriteTransaction<Configuration> removeFlowInvTx)
334             throws ExecutionException, InterruptedException {
335         FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
336         mdsalManager.removeFlow(removeFlowInvTx, preFlowEntity);
337
338         FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
339         if (flowEntity != null) {
340             mdsalManager.removeFlow(removeFlowInvTx, flowEntity);
341         }
342     }
343
344     private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> portIid,
345                                  LogicalDatastoreType dataStoreType) {
346         Optional<RouterPorts> rtrPort =
347                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
348                         dataStoreType, portIid);
349         if (!rtrPort.isPresent()) {
350             LOG.error("getExtNetworkId : Unable to read router port entry for {}", portIid);
351             return null;
352         }
353
354         Uuid extNwId = rtrPort.get().getExternalNetworkId();
355         return extNwId;
356     }
357
358     private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
359         Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
360         if (subnetId != null) {
361             long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
362             if (vpnId != NatConstants.INVALID_ID) {
363                 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
364                 return vpnId;
365             }
366         }
367
368         InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
369                 new NetworksKey(extNwId)).build();
370         Optional<Networks> nw =
371                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
372                         LogicalDatastoreType.CONFIGURATION, nwId);
373         if (!nw.isPresent()) {
374             LOG.error("getVpnId : Unable to read external network for {}", extNwId);
375             return NatConstants.INVALID_ID;
376         }
377
378         Uuid vpnUuid = nw.get().getVpnid();
379         if (vpnUuid == null) {
380             LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
381             return NatConstants.INVALID_ID;
382         }
383
384         //Get the id using the VPN UUID (also vpn instance name)
385         return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
386     }
387
388     private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
389                                       final InternalToExternalPortMap mapping) {
390         LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.key(), mapping);
391
392         final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
393         final PortsKey pKey = identifier.firstKeyOf(Ports.class);
394         String interfaceName = pKey.getPortName();
395
396         InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
397         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
398                 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
399                     tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
400                 NatConstants.NAT_DJC_MAX_RETRIES);
401     }
402
403     private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
404                                       final InternalToExternalPortMap mapping) {
405         LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.key(), mapping);
406
407         final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
408         final PortsKey pKey = identifier.firstKeyOf(Ports.class);
409         String interfaceName = pKey.getPortName();
410
411         InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
412         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
413                 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
414                     tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
415                 NatConstants.NAT_DJC_MAX_RETRIES);
416     }
417
418     private InetAddress getInetAddress(String ipAddr) {
419         InetAddress ipAddress = null;
420         try {
421             ipAddress = InetAddress.getByName(ipAddr);
422         } catch (UnknownHostException e) {
423             LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
424         }
425         return ipAddress;
426     }
427
428     private boolean validateIpMapping(InternalToExternalPortMap mapping) {
429         return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
430     }
431
432     private BigInteger getAssociatedDpnWithExternalInterface(final String routerName, Uuid extNwId, BigInteger dpnId,
433             String interfaceName) {
434         //Get the DPN on which this interface resides
435         if (dpnId == null) {
436             dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
437         }
438         BigInteger updatedDpnId = dpnId;
439         if (updatedDpnId.equals(BigInteger.ZERO)) {
440             LOG.debug("getAssociatedDpnWithExternalInterface : The interface {} is not associated with any dpn",
441                     interfaceName);
442             return updatedDpnId;
443         }
444         ProviderTypes providerType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
445         if (providerType == null) {
446             LOG.warn("getAssociatedDpnWithExternalInterface : Provider Network Type for router {} and"
447                     + " externalNetwork {} is missing.", routerName, extNwId);
448             return updatedDpnId;
449         }
450
451         // For FLAT and VLAN provider networks, we have to ensure that dpn hosting the VM has connectivity
452         // to External Network via provider_mappings. In case the dpn does not have the provider mappings,
453         // traffic from the VM has to be forwarded to the NAPT Switch (which is scheduled based on the provider
454         // mappings) and then sent out on the external Network.
455         if (providerType == ProviderTypes.FLAT || providerType == ProviderTypes.VLAN) {
456             String providerNet = NatUtil.getElanInstancePhysicalNetwok(extNwId.getValue(), dataBroker);
457             boolean isDpnConnected = centralizedSwitchScheduler.isSwitchConnectedToExternal(updatedDpnId, providerNet);
458             if (!isDpnConnected) {
459                 updatedDpnId = centralizedSwitchScheduler.getCentralizedSwitch(routerName);
460             }
461         }
462         return updatedDpnId;
463     }
464
465     void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
466                               final InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
467             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
468         if (!validateIpMapping(mapping)) {
469             LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
470             return;
471         }
472
473         Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
474         if (extNwId == null) {
475             LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
476                     interfaceName);
477             return;
478         }
479
480         // For Overlay Networks, get the DPN on which this interface resides.
481         // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
482         dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId, dpnId, interfaceName);
483         if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
484             LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
485                     + "not be installed", interfaceName, mapping);
486             return;
487         }
488
489         long routerId = NatUtil.getVpnId(dataBroker, routerName);
490         if (routerId == NatConstants.INVALID_ID) {
491             LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
492                     routerName);
493             return;
494         }
495         //Check if the router to vpn association is present
496         //long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
497         Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
498         long associatedVpnId = NatConstants.INVALID_ID;
499         if (associatedVpn == null) {
500             LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
501         } else {
502             LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
503                     routerName, associatedVpn);
504             associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
505             LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
506             //routerId = associatedVpnId;
507         }
508
509         long vpnId = getVpnId(extNwId, mapping.getExternalId());
510         if (vpnId < 0) {
511             LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
512                     + "for fixed ip {}", extNwId, mapping.getInternalIp());
513             return;
514         }
515         //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
516         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
517         if (!isSnatEnabled) {
518             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
519         }
520         //Create the DNAT and SNAT table entries
521         createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
522         createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, confTx);
523         floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, confTx);
524     }
525
526     void createNATFlowEntries(BigInteger dpnId,  String interfaceName, String routerName, Uuid externalNetworkId,
527                               InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx)
528             throws ExecutionException, InterruptedException {
529         String internalIp = mapping.getInternalIp();
530         long routerId = NatUtil.getVpnId(dataBroker, routerName);
531         if (routerId == NatConstants.INVALID_ID) {
532             LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
533                     routerName);
534             return;
535         }
536         //Check if the router to vpn association is present
537         long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
538         if (associatedVpnId == NatConstants.INVALID_ID) {
539             LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
540         } else {
541             LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
542                 routerName, associatedVpnId);
543             //routerId = associatedVpnId;
544         }
545
546         long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
547         if (vpnId < 0) {
548             LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
549             return;
550         }
551         //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
552         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
553         if (!isSnatEnabled) {
554             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
555         }
556         //Create the DNAT and SNAT table entries
557         createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
558         createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, confTx);
559         floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
560                 confTx);
561     }
562
563     void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, String associatedVPN,
564                                   Uuid externalNetworkId, InternalToExternalPortMap mapping)
565             throws ExecutionException, InterruptedException {
566         String internalIp = mapping.getInternalIp();
567         //String segmentId = associatedVPN == null ? routerName : associatedVPN;
568         LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
569                 routerName);
570         long routerId = NatUtil.getVpnId(dataBroker, routerName);
571         if (routerId == NatConstants.INVALID_ID) {
572             LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
573                     routerName);
574             return;
575         }
576         long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
577         LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
578         long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
579         if (vpnId < 0) {
580             LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
581             return;
582         }
583         //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
584         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
585         if (!isSnatEnabled) {
586             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
587         }
588         //Create the DNAT and SNAT table entries
589         FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
590         mdsalManager.installFlow(preFlowEntity);
591
592         FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
593         mdsalManager.installFlow(flowEntity);
594
595         String externalIp = mapping.getExternalIp();
596         preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
597         mdsalManager.installFlow(preFlowEntity);
598
599         flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
600         if (flowEntity != null) {
601             mdsalManager.installFlow(flowEntity);
602         }
603
604     }
605
606     void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
607                               InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
608                               TypedReadWriteTransaction<Configuration> removeFlowInvTx)
609             throws ExecutionException, InterruptedException {
610         Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
611         if (extNwId == null) {
612             LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
613                     interfaceName);
614             return;
615         }
616
617         // For Overlay Networks, get the DPN on which this interface resides.
618         // For FLAT/VLAN Networks, get the DPN with provider_mappings for external network.
619         if (dpnId == null) {
620             dpnId = getAssociatedDpnWithExternalInterface(routerName, extNwId,
621                     NatUtil.getDpnForInterface(interfaceManager, interfaceName), interfaceName);
622             if (dpnId == null || dpnId.equals(BigInteger.ZERO)) {
623                 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
624                         interfaceName);
625                 return;
626             }
627         }
628
629         long routerId = NatUtil.getVpnId(dataBroker, routerName);
630         if (routerId == NatConstants.INVALID_ID) {
631             LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
632                     routerName);
633             return;
634         }
635
636         String internalIp = mapping.getInternalIp();
637         String externalIp = mapping.getExternalIp();
638
639         //Delete the DNAT and SNAT table entries
640         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
641
642         long vpnId = getVpnId(extNwId, mapping.getExternalId());
643         if (vpnId < 0) {
644             LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
645                 + "entry for fixed ip {}", extNwId, internalIp);
646             return;
647         }
648         removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
649         //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
650         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
651         if (!isSnatEnabled) {
652             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
653         }
654         ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
655         if (provType == null) {
656             LOG.error("removeNATFlowEntries : External Network Provider Type missing");
657             return;
658         }
659         if (provType == ProviderTypes.VXLAN) {
660             floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
661                     NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
662             removeOperationalDS(routerName, interfaceName, internalIp);
663             return;
664         }
665         long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
666         if (label < 0) {
667             LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
668                     internalIp, routerId);
669             return;
670         }
671         floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
672                 removeFlowInvTx);
673         removeOperationalDS(routerName, interfaceName, internalIp);
674     }
675
676     void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
677                               InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx)
678             throws ExecutionException, InterruptedException {
679         String internalIp = mapping.getInternalIp();
680         String externalIp = mapping.getExternalIp();
681         long routerId = NatUtil.getVpnId(dataBroker, routerName);
682         if (routerId == NatConstants.INVALID_ID) {
683             LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
684                     routerName);
685             return;
686         }
687
688         long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
689         if (vpnId == NatConstants.INVALID_ID) {
690             LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
691                     vpnName, internalIp);
692         }
693
694         //Delete the DNAT and SNAT table entries
695         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, confTx);
696         removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, confTx);
697         //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
698         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
699         if (!isSnatEnabled) {
700             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, false);
701         }
702         Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
703         ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
704         if (provType == null) {
705             LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
706             return;
707         }
708         if (provType == ProviderTypes.VXLAN) {
709             floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
710                     confTx, provType);
711             removeOperationalDS(routerName, interfaceName, internalIp);
712             return;
713         }
714         long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
715         if (label < 0) {
716             LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
717                     internalIp, routerId);
718             return;
719         }
720         floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
721         removeOperationalDS(routerName, interfaceName, internalIp);
722     }
723
724     protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
725         InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
726             NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
727         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
728                 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
729                 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
730     }
731
732     static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
733                                     String internalIp, String externalIp) {
734
735         LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
736                 internalIp, label);
737         InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
738         Optional<Ports> optPorts =
739                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
740                         LogicalDatastoreType.OPERATIONAL, portsId);
741         InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
742                 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
743                 .setLabel(label).build();
744         if (optPorts.isPresent()) {
745             LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
746                     interfaceName, internalIp);
747             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
748                     .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
749         } else {
750             LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
751                     interfaceName, internalIp);
752             List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
753             intExtPortMapList.add(intExtPortMap);
754             Ports ports = new PortsBuilder().withKey(new PortsKey(interfaceName)).setPortName(interfaceName)
755                     .setInternalToExternalPortMap(intExtPortMapList).build();
756             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
757         }
758     }
759
760     void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
761         LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
762         InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
763                 interfaceName, internalIp);
764         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
765     }
766
767     private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
768
769         LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
770
771         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
772
773         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
774                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
775                 NwConstants.COOKIE_DNAT_TABLE, null, null);
776
777         return flowEntity;
778     }
779
780
781
782     private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
783
784         LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
785
786         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
787
788         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
789                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
790                 NwConstants.COOKIE_DNAT_TABLE, null, null);
791
792         return flowEntity;
793
794     }
795
796     private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
797
798         LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
799
800         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
801
802         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
803                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
804                 NwConstants.COOKIE_DNAT_TABLE, null, null);
805         return flowEntity;
806     }
807
808     private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
809
810         LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
811
812         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
813
814         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
815                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
816                 NwConstants.COOKIE_DNAT_TABLE, null, null);
817
818         return flowEntity;
819     }
820
821     private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName, long routerId,
822             TypedReadWriteTransaction<Configuration> confTx, boolean create)
823             throws ExecutionException, InterruptedException {
824         if (confTx == null) {
825             ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
826                 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
827                 "Error handling default FIB route for DNAT");
828             return;
829         }
830         //Check if the router to bgp-vpn association is present
831         long associatedVpnId = NatConstants.INVALID_ID;
832         Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
833         if (associatedVpn != null) {
834             associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
835         }
836         if (create) {
837             if (associatedVpnId != NatConstants.INVALID_ID) {
838                 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
839                         + "vpn-id {}", dpnId, routerName, associatedVpnId);
840                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
841             } else {
842                 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
843                         + "vpn-id {}", dpnId, routerName, routerId);
844                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
845             }
846         } else {
847             if (associatedVpnId != NatConstants.INVALID_ID) {
848                 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
849                         + "with vpn-id {}", dpnId, routerName, associatedVpnId);
850                 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
851             } else {
852                 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
853                         + "with vpn-id {}", dpnId, routerName, routerId);
854                 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
855             }
856         }
857     }
858 }