2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.natservice.internal;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
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;
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.interfaces.IMdsalApiManager;
35 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
36 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
37 import org.opendaylight.netvirt.elanmanager.api.IElanService;
38 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
39 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
55 public class RouterDpnChangeListener
56 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
58 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
59 private final DataBroker dataBroker;
60 private final ManagedNewTransactionRunner txRunner;
61 private final IMdsalApiManager mdsalManager;
62 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
63 private final NaptSwitchHA naptSwitchHA;
64 private final IdManagerService idManager;
65 private final INeutronVpnManager nvpnManager;
66 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
67 private final IElanService elanManager;
68 private final JobCoordinator coordinator;
69 private final SnatServiceManager natServiceManager;
70 private final NatMode natMode;
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 final JobCoordinator coordinator) {
83 super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
84 this.dataBroker = dataBroker;
85 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
86 this.mdsalManager = mdsalManager;
87 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
88 this.naptSwitchHA = naptSwitchHA;
89 this.idManager = idManager;
90 this.extNetGroupInstaller = extNetGroupInstaller;
91 this.nvpnManager = nvpnManager;
92 this.elanManager = elanManager;
93 this.natServiceManager = natServiceManager;
94 this.coordinator = coordinator;
95 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
101 LOG.info("{} init", getClass().getSimpleName());
102 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
106 protected RouterDpnChangeListener getDataTreeChangeListener() {
107 return RouterDpnChangeListener.this;
111 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
112 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
113 .child(DpnVpninterfacesList.class);
117 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
118 LOG.trace("add : key: {}, value: {}", dpnInfo.key(), dpnInfo);
119 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
120 BigInteger dpnId = dpnInfo.getDpnId();
121 //check router is associated to external network
122 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
123 Optional<Routers> routerData =
124 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
125 LogicalDatastoreType.CONFIGURATION, id);
126 if (routerData.isPresent()) {
127 Routers router = routerData.get();
128 Uuid networkId = router.getNetworkId();
129 if (networkId != null) {
130 if (natMode == NatMode.Conntrack) {
131 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
132 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
133 LOG.warn("add : NAPT switch is not selected.");
136 //If it is for NAPT switch skip as the flows would be already programmed.
137 if (naptSwitch.equals(dpnId)) {
138 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
141 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
142 confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
143 SnatServiceManager.Action.SNAT_ROUTER_ENBL)), LOG, "Error notifying NAT service manager");
145 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
146 if (routerId == NatConstants.INVALID_ID) {
147 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
150 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
151 routerUuid, networkId);
152 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
153 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
154 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
155 installDefaultNatRouteForRouterExternalSubnets(dpnId,
156 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
157 return Collections.emptyList();
160 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
161 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
162 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
163 return Collections.singletonList(
164 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
166 if (vpnName == null) {
167 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
169 if (vpnId == NatConstants.INVALID_ID) {
170 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
173 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
174 //Install default entry in FIB to SNAT table
176 "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
177 dpnId, routerUuid, vpnId);
178 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
180 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
181 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
182 if (vpnId == NatConstants.INVALID_ID) {
183 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
186 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
187 //Install default entry in FIB to SNAT table
188 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
189 + "vpnId {}...", dpnId, routerUuid, vpnId);
190 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
192 if (router.isEnableSnat()) {
193 LOG.info("add : SNAT enabled for router {}", routerUuid);
194 if (extNwProvType == null) {
195 LOG.error("add : External Network Provider Type missing");
198 handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, confTx, extNwProvType);
200 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
204 }, NatConstants.NAT_DJC_MAX_RETRIES);
205 } // end of controller based SNAT
208 LOG.debug("add : Router {} is not associated with External network", routerUuid);
213 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
214 LOG.trace("remove : key: {}, value: {}", dpnInfo.key(), dpnInfo);
215 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
216 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
217 if (routerId == NatConstants.INVALID_ID) {
218 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
221 BigInteger dpnId = dpnInfo.getDpnId();
222 //check router is associated to external network
223 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
224 Optional<Routers> routerData =
225 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
226 LogicalDatastoreType.CONFIGURATION, id);
227 if (routerData.isPresent()) {
228 Routers router = routerData.get();
229 Uuid networkId = router.getNetworkId();
230 if (networkId != null) {
231 if (natMode == NatMode.Conntrack) {
232 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
233 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
234 LOG.warn("remove : NAPT switch is not selected.");
237 //If it is for NAPT switch skip as the flows would be already programmed.
238 if (naptSwitch.equals(dpnId)) {
239 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
242 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
243 confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
244 SnatServiceManager.Action.SNAT_ROUTER_DISBL)), LOG, "Error notifying NAT service manager");
246 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
247 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
248 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
249 return Collections.singletonList(
250 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
252 if (vpnName == null) {
253 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
255 if (vpnId == NatConstants.INVALID_ID) {
256 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
259 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
260 //Remove default entry in FIB
261 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
263 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, confTx);
265 LOG.debug("remove : External vpn associated to router {}", routerUuid);
266 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
267 if (vpnId == NatConstants.INVALID_ID) {
268 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
271 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
272 //Remove default entry in FIB
273 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
275 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
278 if (router.isEnableSnat()) {
279 LOG.info("remove : SNAT enabled for router {}", routerUuid);
280 removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, confTx);
282 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
286 }, NatConstants.NAT_DJC_MAX_RETRIES);
287 } // end of controller based SNAT
293 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
294 DpnVpninterfacesList update) {
295 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
298 void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
299 TypedReadWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
300 //Check if primary and secondary switch are selected, If not select the role
301 //Install select group to NAPT switch
302 //Install default miss entry to NAPT switch
303 BigInteger naptSwitch;
305 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
306 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
307 LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
309 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
311 LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
312 naptSwitch, routerName);
315 LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
317 // When NAPT switch is elected during first VM comes up for the given Router
318 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
319 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
320 idManager, NatConstants.ODL_VNI_POOL_NAME);
323 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
324 if (extRouters != null) {
325 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
326 naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
329 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
331 // Install miss entry (table 26) pointing to table 46
332 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
333 routerVpnId, NatConstants.ADD_FLOW);
334 if (flowEntity == null) {
335 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
339 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
340 mdsalManager.addFlow(confTx, flowEntity);
341 //Removing primary flows from old napt switch
342 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
343 LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
345 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptId, null, confTx);
347 } else if (naptId.equals(dpnId)) {
348 LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
351 LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
355 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
356 routerName, routerId, naptSwitch);
357 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
359 // Install miss entry (table 26) pointing to group
360 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
361 FlowEntity flowEntity =
362 naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
363 routerVpnId, NatConstants.ADD_FLOW);
364 if (flowEntity == null) {
365 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
366 routerName, dpnId, groupId);
369 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
370 dpnId, routerName, groupId);
371 mdsalManager.addFlow(confTx, flowEntity);
374 } catch (InterruptedException | ExecutionException e) {
375 LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", e);
379 // TODO Clean up the exception handling
380 @SuppressWarnings("checkstyle:IllegalCatch")
381 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
382 Uuid extNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
383 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
384 //remove miss entry to NAPT switch
385 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
387 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
388 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
389 if (extNwProvType == null) {
392 //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
393 Map<String, Long> externalIpLabel;
394 if (extNwProvType == ProviderTypes.VXLAN) {
395 externalIpLabel = null;
397 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
399 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
400 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
401 LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
406 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
407 externalIpCache, confTx);
409 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
411 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
412 FlowEntity flowEntity = null;
414 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
415 NatConstants.DEL_FLOW);
416 if (flowEntity == null) {
417 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
418 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
421 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
422 mdsalManager.removeFlow(confTx, flowEntity);
424 } catch (Exception ex) {
425 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
429 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
433 GroupEntity groupEntity = null;
435 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
436 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
437 LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
438 mdsalManager.removeGroup(groupEntity);
439 } catch (Exception ex) {
440 LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
443 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
446 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
447 externalIpLabel, confTx);
448 //remove table 26 flow ppointing to table46
449 FlowEntity flowEntity = null;
451 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
452 NatConstants.DEL_FLOW);
453 if (flowEntity == null) {
454 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
458 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
459 + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
460 mdsalManager.removeFlow(confTx, flowEntity);
462 } catch (Exception ex) {
463 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
467 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
470 //best effort to check IntExt model
471 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
473 } catch (InterruptedException | ExecutionException e) {
474 LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, e);
478 private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
479 if (externalSubnetIds == null) {
480 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
484 for (Uuid subnetId : externalSubnetIds) {
485 long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
486 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
487 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
488 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
489 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
491 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);