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