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