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