Ensure External Connectivity for NAPT Switch
[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.interfaces.IMdsalApiManager;
35 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
36 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
37 import org.opendaylight.netvirt.elanmanager.api.IElanService;
38 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
39 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
40 import org.opendaylight.serviceutils.upgrade.UpgradeState;
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 -> {
147                             natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
148                                     SnatServiceManager.Action.CNT_ROUTER_ENBL);
149                             if (router.isEnableSnat()) {
150                                 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
151                                         SnatServiceManager.Action.SNAT_ROUTER_ENBL);
152                             }
153                         }), LOG, "Error notifying NAT service manager");
154                 } else {
155                     Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
156                     if (routerId == NatConstants.INVALID_ID) {
157                         LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
158                         return;
159                     }
160                     ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
161                             routerUuid, networkId);
162                     if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
163                         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
164                             extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
165                             installDefaultNatRouteForRouterExternalSubnets(dpnId,
166                                     NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
167                             return Collections.emptyList();
168                         });
169                     }
170                     coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
171                         LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
172                         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
173                         return Collections.singletonList(
174                             txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
175                                 Long vpnId;
176                                 if (vpnName == null) {
177                                     LOG.debug("add : Internal vpn associated to router {}", routerUuid);
178                                     vpnId = routerId;
179                                     if (vpnId == NatConstants.INVALID_ID) {
180                                         LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
181                                         return;
182                                     }
183                                     LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
184                                     //Install default entry in FIB to SNAT table
185                                     LOG.info(
186                                         "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
187                                         dpnId, routerUuid, vpnId);
188                                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
189                                 } else {
190                                     LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
191                                     vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
192                                     if (vpnId == NatConstants.INVALID_ID) {
193                                         LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
194                                         return;
195                                     }
196                                     LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
197                                     //Install default entry in FIB to SNAT table
198                                     LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
199                                         + "vpnId {}...", dpnId, routerUuid, vpnId);
200                                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
201                                 }
202                                 if (router.isEnableSnat()) {
203                                     LOG.info("add : SNAT enabled for router {}", routerUuid);
204                                     if (extNwProvType == null) {
205                                         LOG.error("add : External Network Provider Type missing");
206                                         return;
207                                     }
208                                     handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, confTx, extNwProvType);
209                                 } else {
210                                     LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
211                                         routerUuid, dpnId);
212                                 }
213                             }));
214                     }, NatConstants.NAT_DJC_MAX_RETRIES);
215                 } // end of controller based SNAT
216             }
217         } else {
218             LOG.debug("add : Router {} is not associated with External network", routerUuid);
219         }
220     }
221
222     @Override
223     protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
224         LOG.trace("remove : key: {}, value: {}", dpnInfo.key(), dpnInfo);
225         final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
226         Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
227         if (routerId == NatConstants.INVALID_ID) {
228             LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
229             return;
230         }
231         BigInteger dpnId = dpnInfo.getDpnId();
232         //check router is associated to external network
233         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
234         Optional<Routers> routerData =
235                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
236                         LogicalDatastoreType.CONFIGURATION, id);
237         if (routerData.isPresent()) {
238             Routers router = routerData.get();
239             Uuid networkId = router.getNetworkId();
240             if (networkId != null) {
241                 if (natMode == NatMode.Conntrack) {
242                     BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
243                     if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
244                         LOG.warn("remove : NAPT switch is not selected.");
245                         return;
246                     }
247                     //If it is for NAPT switch skip as the flows would be already programmed.
248                     if (naptSwitch.equals(dpnId)) {
249                         LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
250                         return;
251                     }
252                     ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
253                         confTx -> {
254                             natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
255                                     SnatServiceManager.Action.CNT_ROUTER_DISBL);
256                             if (router.isEnableSnat()) {
257                                 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
258                                         SnatServiceManager.Action.SNAT_ROUTER_DISBL);
259                             }
260                         }), LOG, "Error notifying NAT service manager");
261                 } else {
262                     coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
263                         LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
264                         Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
265                         return Collections.singletonList(
266                             txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
267                                 Long vpnId;
268                                 if (vpnName == null) {
269                                     LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
270                                     vpnId = routerId;
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, confTx);
280                                 } else {
281                                     LOG.debug("remove : External vpn associated to router {}", routerUuid);
282                                     vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
283                                     if (vpnId == NatConstants.INVALID_ID) {
284                                         LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
285                                         return;
286                                     }
287                                     LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
288                                     //Remove default entry in FIB
289                                     LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
290                                         vpnName);
291                                     snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
292                                 }
293
294                                 if (router.isEnableSnat()) {
295                                     LOG.info("remove : SNAT enabled for router {}", routerUuid);
296                                     removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, confTx);
297                                 } else {
298                                     LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
299                                         routerUuid, dpnId);
300                                 }
301                             }));
302                     }, NatConstants.NAT_DJC_MAX_RETRIES);
303                 } // end of controller based SNAT
304             }
305         }
306     }
307
308     @Override
309     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
310                           DpnVpninterfacesList update) {
311         LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
312     }
313
314     void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
315         TypedReadWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
316        //Check if primary and secondary switch are selected, If not select the role
317         //Install select group to NAPT switch
318         //Install default miss entry to NAPT switch
319         BigInteger naptSwitch;
320         try {
321             BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
322             if (naptId == null || naptId.equals(BigInteger.ZERO)
323                     || !NatUtil.getSwitchStatus(dataBroker, naptId) && !upgradeState.isUpgradeInProgress()) {
324                 LOG.debug("handleSNATForDPN : NaptSwitch is down or not selected for router {},naptId {}",
325                         routerName, naptId);
326                 naptSwitch = dpnId;
327                 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
328                 if (!naptstatus) {
329                     LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
330                             naptSwitch, routerName);
331                     return;
332                 }
333                 LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
334
335                 // When NAPT switch is elected during first VM comes up for the given Router
336                 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
337                     NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
338                             idManager, NatConstants.ODL_VNI_POOL_NAME);
339                 }
340
341                 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
342                 if (extRouters != null) {
343                     NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
344                     naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
345                 }
346
347                 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
348
349                 // Install miss entry (table 26) pointing to table 46
350                 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
351                         routerVpnId, NatConstants.ADD_FLOW);
352                 if (flowEntity == null) {
353                     LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
354                             routerName, dpnId);
355                     return;
356                 }
357                 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
358                 mdsalManager.addFlow(confTx, flowEntity);
359                 //Removing primary flows from old napt switch
360                 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
361                     LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
362                             naptId, routerName);
363                     naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptId, null, confTx);
364                 }
365             } else if (naptId.equals(dpnId)) {
366                 LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
367             } else {
368                 naptSwitch = naptId;
369                 LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
370                         naptId, routerName);
371
372                 //installing group
373                 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
374                         routerName, routerId, naptSwitch);
375                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
376
377                 // Install miss entry (table 26) pointing to group
378                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
379                 FlowEntity flowEntity =
380                         naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
381                                 routerVpnId, NatConstants.ADD_FLOW);
382                 if (flowEntity == null) {
383                     LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
384                             routerName, dpnId, groupId);
385                     return;
386                 }
387                 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
388                         dpnId, routerName, groupId);
389                 mdsalManager.addFlow(confTx, flowEntity);
390             }
391
392         } catch (InterruptedException | ExecutionException e) {
393             LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", e);
394         }
395     }
396
397     // TODO Clean up the exception handling
398     @SuppressWarnings("checkstyle:IllegalCatch")
399     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
400             Uuid extNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
401         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
402         //remove miss entry to NAPT switch
403         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
404
405         Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
406         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
407         if (extNwProvType == null) {
408             return;
409         }
410         //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
411         Map<String, Long> externalIpLabel;
412         if (extNwProvType == ProviderTypes.VXLAN) {
413             externalIpLabel = null;
414         } else {
415             externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
416         }
417         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
418         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
419             LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
420             return;
421         }
422         try {
423             boolean naptStatus =
424                 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
425                         externalIpCache, confTx);
426             if (!naptStatus) {
427                 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
428                     dpnId, routerName);
429                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
430                 FlowEntity flowEntity = null;
431                 try {
432                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
433                         NatConstants.DEL_FLOW);
434                     if (flowEntity == null) {
435                         LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
436                                 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
437                         return;
438                     }
439                     LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
440                     mdsalManager.removeFlow(confTx, flowEntity);
441
442                 } catch (Exception ex) {
443                     LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
444                         flowEntity, ex);
445                     return;
446                 }
447                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
448                     dpnId, routerName);
449
450                 //remove group
451                 GroupEntity groupEntity = null;
452                 try {
453                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
454                         GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
455                     LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
456                     mdsalManager.removeGroup(groupEntity);
457                 } catch (Exception ex) {
458                     LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
459                     return;
460                 }
461                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
462                     dpnId, routerName);
463             } else {
464                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
465                         externalIpLabel, confTx);
466                 //remove table 26 flow ppointing to table46
467                 FlowEntity flowEntity = null;
468                 try {
469                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
470                         NatConstants.DEL_FLOW);
471                     if (flowEntity == null) {
472                         LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
473                                 routerName, dpnId);
474                         return;
475                     }
476                     LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
477                         + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
478                     mdsalManager.removeFlow(confTx, flowEntity);
479
480                 } catch (Exception ex) {
481                     LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
482                         flowEntity, ex);
483                     return;
484                 }
485                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
486                     dpnId, routerName);
487
488                 //best effort to check IntExt model
489                 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
490             }
491         } catch (InterruptedException | ExecutionException e) {
492             LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, e);
493         }
494     }
495
496     private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
497         if (externalSubnetIds == null) {
498             LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
499             return;
500         }
501
502         for (Uuid subnetId : externalSubnetIds) {
503             long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
504             if (vpnIdForSubnet != NatConstants.INVALID_ID) {
505                 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
506                         + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
507                 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
508             } else {
509                 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);
510             }
511         }
512     }
513 }