Bug 9193 - In conntrack SNAT , flows are programmed twice on a router
[netvirt.git] / vpnservice / natservice / 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
13 import java.math.BigInteger;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.List;
18 import java.util.Map;
19 import javax.annotation.PostConstruct;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22
23 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
24 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
25 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
26 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
27 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
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.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.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.dpn.vpninterfaces.list.RouterInterfaces;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 @Singleton
56 public class RouterDpnChangeListener
57         extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener>
58         implements AutoCloseable {
59
60     private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
61     private final DataBroker dataBroker;
62     private final IMdsalApiManager mdsalManager;
63     private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
64     private final NaptSwitchHA naptSwitchHA;
65     private final IdManagerService idManager;
66     private final INeutronVpnManager nvpnManager;
67     private final ExternalNetworkGroupInstaller extNetGroupInstaller;
68     private final IElanService elanManager;
69     private SnatServiceManager natServiceManager;
70     private NatMode natMode = NatMode.Controller;
71
72     @Inject
73     public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
74                                    final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
75                                    final NaptSwitchHA naptSwitchHA,
76                                    final IdManagerService idManager,
77                                    final ExternalNetworkGroupInstaller extNetGroupInstaller,
78                                    final INeutronVpnManager nvpnManager,
79                                    final SnatServiceManager natServiceManager,
80                                    final NatserviceConfig config,
81                                    final IElanService elanManager) {
82         super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
83         this.dataBroker = dataBroker;
84         this.mdsalManager = mdsalManager;
85         this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
86         this.naptSwitchHA = naptSwitchHA;
87         this.idManager = idManager;
88         this.extNetGroupInstaller = extNetGroupInstaller;
89         this.nvpnManager = nvpnManager;
90         this.elanManager = elanManager;
91         this.natServiceManager = natServiceManager;
92         if (config != null) {
93             this.natMode = config.getNatMode();
94         }
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.getKey(), dpnInfo);
118         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
119         BigInteger dpnId = dpnInfo.getDpnId();
120         //check router is associated to external network
121         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
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 a router port skip the notify.
136                     for (Uuid subnetUuid :router.getSubnetIds()) {
137                         try {
138                             Optional<Subnetmap> subnetMapEntry =
139                                     SingleTransactionDataBroker.syncReadOptional(dataBroker,
140                                             LogicalDatastoreType.CONFIGURATION, getSubnetMapIdentifier(subnetUuid));
141                             if (subnetMapEntry.isPresent()) {
142                                 String routerPortUuid = subnetMapEntry.get().getRouterInterfacePortId().getValue();
143                                 List<RouterInterfaces> routerInterfaces = dpnInfo.getRouterInterfaces();
144                                 for (RouterInterfaces routerInterface : routerInterfaces) {
145                                     if (routerPortUuid.equals(routerInterface.getInterface())) {
146                                         return;
147                                     }
148                                 }
149                             }
150                         } catch (ReadFailedException e) {
151                             LOG.warn("add : The subnet map entry is not present.");
152                             return;
153                         }
154
155                     }
156                     natServiceManager.notify(router, naptSwitch, dpnId,
157                             SnatServiceManager.Action.SNAT_ROUTER_ENBL);
158                 } else {
159                     WriteTransaction writeFlowInvTx = dataBroker.newWriteOnlyTransaction();
160                     WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
161                     LOG.debug("add : Router {} is associated with ext nw {}", routerId, networkId);
162                     Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
163                     Long vpnId;
164                     if (vpnName == null) {
165                         LOG.debug("add : Internal vpn associated to router {}", routerId);
166                         vpnId = NatUtil.getVpnId(dataBroker, routerId);
167                         if (vpnId == NatConstants.INVALID_ID) {
168                             LOG.error("add : Invalid vpnId returned for routerName {}", routerId);
169                             return;
170                         }
171                         LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerId);
172                         //Install default entry in FIB to SNAT table
173                         LOG.info("add : Installing default route in FIB on dpn {} for router {} with vpn {}",
174                                 dpnId, routerId, vpnId);
175                         installDefaultNatRouteForRouterExternalSubnets(dpnId,
176                                 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
177                         snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, writeFlowInvTx);
178                     } else {
179                         LOG.debug("add : External BGP vpn associated to router {}", routerId);
180                         vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
181                         if (vpnId == NatConstants.INVALID_ID) {
182                             LOG.error("add : Invalid vpnId returned for routerName {}", routerId);
183                             return;
184                         }
185                         Long routId = NatUtil.getVpnId(dataBroker, routerId);
186                         if (routId == NatConstants.INVALID_ID) {
187                             LOG.error("add : Invalid routId returned for routerName {}", routerId);
188                             return;
189                         }
190                         LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerId);
191                         //Install default entry in FIB to SNAT table
192                         LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with vpnId {}...",
193                                 dpnId, routerId, vpnId);
194                         installDefaultNatRouteForRouterExternalSubnets(dpnId,
195                                 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
196                         snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routId, writeFlowInvTx);
197                     }
198                     extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
199
200                     if (router.isEnableSnat()) {
201                         LOG.info("add : SNAT enabled for router {}", routerId);
202                         handleSNATForDPN(dpnId, routerId, vpnId, writeFlowInvTx, removeFlowInvTx);
203                     } else {
204                         LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}", routerId, dpnId);
205                     }
206                     List<ListenableFuture<Void>> futures = new ArrayList<>();
207                     futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
208                     futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
209                 } // end of controller based SNAT
210             }
211         } else {
212             LOG.debug("add : Router {} is not associated with External network", routerId);
213         }
214     }
215
216     @Override
217     protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
218         LOG.trace("remove : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
219         final String routerId = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
220         BigInteger dpnId = dpnInfo.getDpnId();
221         //check router is associated to external network
222         InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerId);
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                     natServiceManager.notify(router, naptSwitch, dpnId,
237                             SnatServiceManager.Action.SNAT_ROUTER_DISBL);
238                 } else {
239                     WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
240                     LOG.debug("remove : Router {} is associated with ext nw {}", routerId, networkId);
241                     Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerId);
242                     Long vpnId;
243                     if (vpnName == null) {
244                         LOG.debug("remove : Internal vpn associated to router {}", routerId);
245                         vpnId = NatUtil.getVpnId(dataBroker, routerId);
246                         if (vpnId == NatConstants.INVALID_ID) {
247                             LOG.error("remove : Invalid vpnId returned for routerName {}", routerId);
248                             return;
249                         }
250                         LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerId);
251                         //Remove default entry in FIB
252                         LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
253                         snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, removeFlowInvTx);
254                     } else {
255                         LOG.debug("remove : External vpn associated to router {}", routerId);
256                         vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
257                         if (vpnId == NatConstants.INVALID_ID) {
258                             LOG.error("remove : Invalid vpnId returned for routerName {}", routerId);
259                             return;
260                         }
261                         Long routId = NatUtil.getVpnId(dataBroker, routerId);
262                         if (routId == NatConstants.INVALID_ID) {
263                             LOG.error("remove : Invalid routId returned for routerName {}", routerId);
264                             return;
265                         }
266                         LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerId);
267                         //Remove default entry in FIB
268                         LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId, vpnName);
269                         snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routId, removeFlowInvTx);
270                     }
271
272                     if (router.isEnableSnat()) {
273                         LOG.info("remove : SNAT enabled for router {}", routerId);
274                         removeSNATFromDPN(dpnId, routerId, vpnId, removeFlowInvTx);
275                     } else {
276                         LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
277                                 routerId, dpnId);
278                     }
279                     List<ListenableFuture<Void>> futures = new ArrayList<>();
280                     futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
281                 } // end of controller based SNAT
282             }
283         }
284     }
285
286     @Override
287     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
288                           DpnVpninterfacesList update) {
289         LOG.trace("Update key: {}, original: {}, update: {}", update.getKey(), original, update);
290     }
291
292     // TODO Clean up the exception handling
293     @SuppressWarnings("checkstyle:IllegalCatch")
294     void handleSNATForDPN(BigInteger dpnId, String routerName, Long routerVpnId, WriteTransaction writeFlowInvTx,
295                           WriteTransaction removeFlowInvTx) {
296        //Check if primary and secondary switch are selected, If not select the role
297         //Install select group to NAPT switch
298         //Install default miss entry to NAPT switch
299         BigInteger naptSwitch;
300         try {
301             Long routerId = NatUtil.getVpnId(dataBroker, routerName);
302             if (routerId == NatConstants.INVALID_ID) {
303                 LOG.error("handleSNATForDPN : Invalid routerId returned for routerName {}", routerName);
304                 return;
305             }
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 (elanManager.isOpenStackVniSemanticsEnforced()) {
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, routerName);
327                     naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
328                 }
329
330                 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
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.addFlowToTx(flowEntity, writeFlowInvTx);
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, naptId, null, removeFlowInvTx);
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, naptSwitch);
358                 if (bucketInfo == null) {
359                     LOG.error("handleSNATForDPN:Failed to populate bucketInfo for dpnId {},routername {},naptSwitch {}",
360                             dpnId, routerName, naptSwitch);
361                     return;
362                 }
363                 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
364
365                 // Install miss entry (table 26) pointing to group
366                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
367                 FlowEntity flowEntity =
368                         naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
369                                 routerVpnId, NatConstants.ADD_FLOW);
370                 if (flowEntity == null) {
371                     LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
372                             routerName, dpnId, groupId);
373                     return;
374                 }
375                 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
376                         dpnId, routerName, groupId);
377                 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
378             }
379
380         } catch (Exception ex) {
381             LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
382         }
383     }
384
385     // TODO Clean up the exception handling
386     @SuppressWarnings("checkstyle:IllegalCatch")
387     void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerVpnId, WriteTransaction removeFlowInvTx) {
388         //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
389         //remove miss entry to NAPT switch
390         //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
391
392         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
393         if (routerId == NatConstants.INVALID_ID) {
394             LOG.error("removeSNATFromDPN : Invalid routerId returned for routerName {}", routerName);
395             return;
396         }
397         Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
398         ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName);
399         if (extNwProvType == null) {
400             return;
401         }
402         //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
403         Map<String, Long> externalIpLabel;
404         if (extNwProvType == ProviderTypes.VXLAN) {
405             externalIpLabel = null;
406         } else {
407             externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
408         }
409         BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
410         if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
411             LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
412             return;
413         }
414         try {
415             boolean naptStatus =
416                 naptSwitchHA.isNaptSwitchDown(routerName, dpnId, naptSwitch, routerVpnId, externalIpCache,
417                         removeFlowInvTx);
418             if (!naptStatus) {
419                 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
420                     dpnId, routerName);
421                 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
422                 FlowEntity flowEntity = null;
423                 try {
424                     flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
425                         NatConstants.DEL_FLOW);
426                     if (flowEntity == null) {
427                         LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
428                                 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
429                         return;
430                     }
431                     LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
432                     mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
433
434                 } catch (Exception ex) {
435                     LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
436                         flowEntity, ex);
437                     return;
438                 }
439                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
440                     dpnId, routerName);
441
442                 //remove group
443                 GroupEntity groupEntity = null;
444                 try {
445                     groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
446                         GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
447                     LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
448                     mdsalManager.removeGroup(groupEntity);
449                 } catch (Exception ex) {
450                     LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
451                     return;
452                 }
453                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
454                     dpnId, routerName);
455             } else {
456                 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, naptSwitch, externalIpLabel, removeFlowInvTx);
457                 //remove table 26 flow ppointing to table46
458                 FlowEntity flowEntity = null;
459                 try {
460                     flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
461                         NatConstants.DEL_FLOW);
462                     if (flowEntity == null) {
463                         LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
464                                 routerName, dpnId);
465                         return;
466                     }
467                     LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
468                         + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
469                     mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
470
471                 } catch (Exception ex) {
472                     LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
473                         flowEntity, ex);
474                     return;
475                 }
476                 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
477                     dpnId, routerName);
478
479                 //best effort to check IntExt model
480                 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, removeFlowInvTx);
481             }
482         } catch (Exception ex) {
483             LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
484         }
485     }
486
487     private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
488         if (externalSubnetIds == null) {
489             LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
490             return;
491         }
492
493         for (Uuid subnetId : externalSubnetIds) {
494             long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
495             if (vpnIdForSubnet != NatConstants.INVALID_ID) {
496                 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
497                         + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
498                 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue(),
499                         idManager);
500             } else {
501                 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);
502             }
503         }
504     }
505
506     private InstanceIdentifier<Subnetmap> getSubnetMapIdentifier(Uuid subnetId) {
507         return InstanceIdentifier.builder(Subnetmaps.class).child(Subnetmap.class,
508                 new SubnetmapKey(subnetId)).build();
509     }
510 }