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