Bug9016:Using Single Transaction during NAPT SwitchOver
[netvirt.git] / vpnservice / natservice / natservice-impl / src / main / java / org / opendaylight / netvirt / natservice / internal / RouterDpnChangeListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Map;
19 import javax.annotation.PostConstruct;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.mdsalutil.BucketInfo;
29 import org.opendaylight.genius.mdsalutil.FlowEntity;
30 import org.opendaylight.genius.mdsalutil.GroupEntity;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
33 import org.opendaylight.netvirt.elanmanager.api.IElanService;
34 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
35 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 @Singleton
51 public class RouterDpnChangeListener
52         extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
53         implements AutoCloseable {
54
55     private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
56     private final DataBroker dataBroker;
57     private final IMdsalApiManager mdsalManager;
58     private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
59     private final NaptSwitchHA naptSwitchHA;
60     private final IdManagerService idManager;
61     private final INeutronVpnManager nvpnManager;
62     private final ExternalNetworkGroupInstaller extNetGroupInstaller;
63     private final IElanService elanManager;
64     private SnatServiceManager natServiceManager;
65     private NatMode natMode = NatMode.Controller;
66
67     @Inject
68     public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
69                                    final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
70                                    final NaptSwitchHA naptSwitchHA,
71                                    final IdManagerService idManager,
72                                    final ExternalNetworkGroupInstaller extNetGroupInstaller,
73                                    final INeutronVpnManager nvpnManager,
74                                    final SnatServiceManager natServiceManager,
75                                    final NatserviceConfig config,
76                                    final IElanService elanManager) {
77         super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
78         this.dataBroker = dataBroker;
79         this.mdsalManager = mdsalManager;
80         this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
81         this.naptSwitchHA = naptSwitchHA;
82         this.idManager = idManager;
83         this.extNetGroupInstaller = extNetGroupInstaller;
84         this.nvpnManager = nvpnManager;
85         this.elanManager = elanManager;
86         this.natServiceManager = natServiceManager;
87         if (config != null) {
88             this.natMode = config.getNatMode();
89         }
90     }
91
92     @Override
93     @PostConstruct
94     public void init() {
95         LOG.info("{} init", getClass().getSimpleName());
96         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
97     }
98
99     @Override
100     protected RouterDpnChangeListener getDataTreeChangeListener() {
101         return RouterDpnChangeListener.this;
102     }
103
104     @Override
105     protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
106         return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
107             .child(DpnVpninterfacesList.class);
108     }
109
110     @Override
111     protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
112         LOG.trace("add : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
113         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
114         BigInteger dpnId = dpnInfo.getDpnId();
115         //check router is associated to external network
116         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
117         Optional<Routers> routerData =
118                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
119                         LogicalDatastoreType.CONFIGURATION, id);
120         if (routerData.isPresent()) {
121             Routers router = routerData.get();
122             Uuid networkId = router.getNetworkId();
123             if (networkId != null) {
124                 if (natMode == NatMode.Conntrack) {
125                     BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
126                     if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
127                         LOG.warn("add : NAPT switch is not selected.");
128                         return;
129                     }
130                     natServiceManager.notify(router, naptSwitch, dpnId,
131                             SnatServiceManager.Action.SNAT_ROUTER_ENBL);
132                 } else {
133                     WriteTransaction writeFlowInvTx = dataBroker.newWriteOnlyTransaction();
134                     WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
135                     LOG.debug("add : Router {} is associated with ext nw {}", routerId, networkId);
136                     Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
137                     Long vpnId;
138                     if (vpnName == null) {
139                         LOG.debug("add : Internal vpn associated to router {}", routerId);
140                         vpnId = NatUtil.getVpnId(dataBroker, routerId);
141                         if (vpnId == NatConstants.INVALID_ID) {
142                             LOG.error("add : Invalid vpnId returned for routerName {}", routerId);
143                             return;
144                         }
145                         LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerId);
146                         //Install default entry in FIB to SNAT table
147                         LOG.info("add : Installing default route in FIB on dpn {} for router {} with vpn {}",
148                                 dpnId, routerId, vpnId);
149                         installDefaultNatRouteForRouterExternalSubnets(dpnId,
150                                 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
151                         snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, writeFlowInvTx);
152                     } else {
153                         LOG.debug("add : External BGP vpn associated to router {}", routerId);
154                         vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
155                         if (vpnId == NatConstants.INVALID_ID) {
156                             LOG.error("add : Invalid vpnId returned for routerName {}", routerId);
157                             return;
158                         }
159                         Long routId = NatUtil.getVpnId(dataBroker, routerId);
160                         if (routId == NatConstants.INVALID_ID) {
161                             LOG.error("add : Invalid routId returned for routerName {}", routerId);
162                             return;
163                         }
164                         LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerId);
165                         //Install default entry in FIB to SNAT table
166                         LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with vpnId {}...",
167                                 dpnId, routerId, vpnId);
168                         installDefaultNatRouteForRouterExternalSubnets(dpnId,
169                                 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
170                         snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId, writeFlowInvTx);
171                     }
172                     extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
173
174                     if (router.isEnableSnat()) {
175                         LOG.info("add : SNAT enabled for router {}", routerId);
176                         handleSNATForDPN(dpnId, routerId, vpnId, writeFlowInvTx, removeFlowInvTx);
177                     } else {
178                         LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
179                     }
180                     List<ListenableFuture<Void>> futures = new ArrayList<>();
181                     futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
182                     futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
183                 } // end of controller based SNAT
184             }
185         } else {
186             LOG.debug("add : Router {} is not associated with External network", routerId);
187         }
188     }
189
190     @Override
191     protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
192         LOG.trace("remove : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
193         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
194         BigInteger dpnId = dpnInfo.getDpnId();
195         //check router is associated to external network
196         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
197         Optional<Routers> routerData =
198                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
199                         LogicalDatastoreType.CONFIGURATION, id);
200         if (routerData.isPresent()) {
201             Routers router = routerData.get();
202             Uuid networkId = router.getNetworkId();
203             if (networkId != null) {
204                 if (natMode == NatMode.Conntrack) {
205                     BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
206                     if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
207                         LOG.warn("remove : NAPT switch is not selected.");
208                         return;
209                     }
210                     natServiceManager.notify(router, naptSwitch, dpnId,
211                             SnatServiceManager.Action.SNAT_ROUTER_DISBL);
212                 } else {
213                     WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
214                     LOG.debug("remove : Router {} is associated with ext nw {}", routerId, networkId);
215                     Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
216                     Long vpnId;
217                     if (vpnName == null) {
218                         LOG.debug("remove : Internal vpn associated to router {}", routerId);
219                         vpnId = NatUtil.getVpnId(dataBroker, routerId);
220                         if (vpnId == NatConstants.INVALID_ID) {
221                             LOG.error("remove : Invalid vpnId returned for routerName {}", routerId);
222                             return;
223                         }
224                         LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerId);
225                         //Remove default entry in FIB
226                         LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
227                         snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, removeFlowInvTx);
228                     } else {
229                         LOG.debug("remove : External vpn associated to router {}", routerId);
230                         vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
231                         if (vpnId == NatConstants.INVALID_ID) {
232                             LOG.error("remove : Invalid vpnId returned for routerName {}", routerId);
233                             return;
234                         }
235                         Long routId = NatUtil.getVpnId(dataBroker, routerId);
236                         if (routId == NatConstants.INVALID_ID) {
237                             LOG.error("remove : Invalid routId returned for routerName {}", routerId);
238                             return;
239                         }
240                         LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerId);
241                         //Remove default entry in FIB
242                         LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
243                         snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routId, removeFlowInvTx);
244                     }
245
246                     if (router.isEnableSnat()) {
247                         LOG.info("remove : SNAT enabled for router {}", routerId);
248                         removeSNATFromDPN(dpnId, routerId, vpnId, removeFlowInvTx);
249                     } else {
250                         LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
251                                 routerId, dpnId);
252                     }
253                     List<ListenableFuture<Void>> futures = new ArrayList<>();
254                     futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
255                 } // end of controller based SNAT
256             }
257         }
258     }
259
260     @Override
261     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
262                           DpnVpninterfacesList update) {
263         LOG.trace("Update key: {}, original: {}, update: {}", update.getKey(), original, update);
264     }
265
266     // TODO Clean up the exception handling
267     @SuppressWarnings("checkstyle:IllegalCatch")
268     void handleSNATForDPN(BigInteger dpnId, String routerName, Long routerVpnId, WriteTransaction writeFlowInvTx,
269                           WriteTransaction removeFlowInvTx) {
270        //Check if primary and secondary switch are selected, If not select the role
271         //Install select group to NAPT switch
272         //Install default miss entry to NAPT switch
273         BigInteger naptSwitch;
274         try {
275             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
276             if (routerId == NatConstants.INVALID_ID) {
277                 LOG.error("handleSNATForDPN : Invalid routerId returned for routerName {}", routerName);
278                 return;
279             }
280             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
281             if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
282                 LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
283                 naptSwitch = dpnId;
284                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
285                 if (!naptstatus) {
286                     LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
287                             naptSwitch, routerName);
288                     return;
289                 }
290                 LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
291
292                 // When NAPT switch is elected during first VM comes up for the given Router
293                 if (elanManager.isOpenStackVniSemanticsEnforced()) {
294                     NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
295                             idManager, NatConstants.ODL_VNI_POOL_NAME);
296                 }
297
298                 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
299                 if (extRouters != null) {
300                     NatUtil.createRouterIdsConfigDS(dataBroker, routerName);
301                     naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
302                 }
303
304                 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
305
306                 // Install miss entry (table 26) pointing to table 46
307                 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
308                         routerVpnId, NatConstants.ADD_FLOW);
309                 if (flowEntity == null) {
310                     LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
311                             routerName, dpnId);
312                     return;
313                 }
314                 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
315                 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
316                 //Removing primary flows from old napt switch
317                 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
318                     LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
319                             naptId, routerName);
320                     naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptId, null, removeFlowInvTx);
321                 }
322             } else if (naptId.equals(dpnId)) {
323                 LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
324             } else {
325                 naptSwitch = naptId;
326                 LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
327                         naptId, routerName);
328
329                 //installing group
330                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
331                         routerName, naptSwitch);
332                 if (bucketInfo == null) {
333                     LOG.error("handleSNATForDPN:Failed to populate bucketInfo for dpnId {},routername {},naptSwitch {}",
334                             dpnId, routerName, naptSwitch);
335                     return;
336                 }
337                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
338
339                 // Install miss entry (table 26) pointing to group
340                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
341                 FlowEntity flowEntity =
342                         naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
343                                 routerVpnId, NatConstants.ADD_FLOW);
344                 if (flowEntity == null) {
345                     LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
346                             routerName, dpnId, groupId);
347                     return;
348                 }
349                 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
350                         dpnId, routerName, groupId);
351                 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
352             }
353
354         } catch (Exception ex) {
355             LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
356         }
357     }
358
359     // TODO Clean up the exception handling
360     @SuppressWarnings("checkstyle:IllegalCatch")
361     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, WriteTransaction removeFlowInvTx) {
362         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
363         //remove miss entry to NAPT switch
364         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
365
366         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
367         if (routerId == NatConstants.INVALID_ID) {
368             LOG.error("removeSNATFromDPN : Invalid routerId returned for routerName {}", routerName);
369             return;
370         }
371         Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
372         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
373         if (extNwProvType == null) {
374             return;
375         }
376         //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
377         Map<String, Long> externalIpLabel;
378         if (extNwProvType == ProviderTypes.VXLAN) {
379             externalIpLabel = null;
380         } else {
381             externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
382         }
383         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
384         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
385             LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
386             return;
387         }
388         try {
389             boolean naptStatus =
390                 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache,
391                         removeFlowInvTx);
392             if (!naptStatus) {
393                 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
394                     dpnId, routerName);
395                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
396                 FlowEntity flowEntity = null;
397                 try {
398                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
399                         NatConstants.DEL_FLOW);
400                     if (flowEntity == null) {
401                         LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
402                                 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
403                         return;
404                     }
405                     LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
406                     mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
407
408                 } catch (Exception ex) {
409                     LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
410                         flowEntity, ex);
411                     return;
412                 }
413                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
414                     dpnId, routerName);
415
416                 //remove group
417                 GroupEntity groupEntity = null;
418                 try {
419                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
420                         GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
421                     LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
422                     mdsalManager.removeGroup(groupEntity);
423                 } catch (Exception ex) {
424                     LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
425                     return;
426                 }
427                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
428                     dpnId, routerName);
429             } else {
430                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch, externalIpLabel, removeFlowInvTx);
431                 //remove table 26 flow ppointing to table46
432                 FlowEntity flowEntity = null;
433                 try {
434                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
435                         NatConstants.DEL_FLOW);
436                     if (flowEntity == null) {
437                         LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
438                                 routerName, dpnId);
439                         return;
440                     }
441                     LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
442                         + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
443                     mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
444
445                 } catch (Exception ex) {
446                     LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
447                         flowEntity, ex);
448                     return;
449                 }
450                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
451                     dpnId, routerName);
452
453                 //best effort to check IntExt model
454                 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, removeFlowInvTx);
455             }
456         } catch (Exception ex) {
457             LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
458         }
459     }
460
461     private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
462         if (externalSubnetIds == null) {
463             LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
464             return;
465         }
466
467         for (Uuid subnetId : externalSubnetIds) {
468             long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
469             if (vpnIdForSubnet != NatConstants.INVALID_ID) {
470                 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
471                         + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
472                 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue(),
473                         idManager);
474             } else {
475                 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);
476             }
477         }
478     }
479 }