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