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 com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
18 import javax.annotation.PostConstruct;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
28 import org.opendaylight.genius.mdsalutil.BucketInfo;
29 import org.opendaylight.genius.mdsalutil.FlowEntity;
30 import org.opendaylight.genius.mdsalutil.GroupEntity;
31 import org.opendaylight.genius.mdsalutil.MDSALUtil;
32 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
33 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
34 import org.opendaylight.netvirt.elanmanager.api.IElanService;
35 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
36 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 public class RouterDpnChangeListener
53 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
55 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
56 private final DataBroker dataBroker;
57 private final ManagedNewTransactionRunner txRunner;
58 private final IMdsalApiManager mdsalManager;
59 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
60 private final NaptSwitchHA naptSwitchHA;
61 private final IdManagerService idManager;
62 private final INeutronVpnManager nvpnManager;
63 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
64 private final IElanService elanManager;
65 private final JobCoordinator coordinator;
66 private final SnatServiceManager natServiceManager;
67 private final NatMode natMode;
70 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
71 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
72 final NaptSwitchHA naptSwitchHA,
73 final IdManagerService idManager,
74 final ExternalNetworkGroupInstaller extNetGroupInstaller,
75 final INeutronVpnManager nvpnManager,
76 final SnatServiceManager natServiceManager,
77 final NatserviceConfig config,
78 final IElanService elanManager,
79 final JobCoordinator coordinator) {
80 super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
81 this.dataBroker = dataBroker;
82 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
83 this.mdsalManager = mdsalManager;
84 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
85 this.naptSwitchHA = naptSwitchHA;
86 this.idManager = idManager;
87 this.extNetGroupInstaller = extNetGroupInstaller;
88 this.nvpnManager = nvpnManager;
89 this.elanManager = elanManager;
90 this.natServiceManager = natServiceManager;
91 this.coordinator = coordinator;
92 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
98 LOG.info("{} init", getClass().getSimpleName());
99 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
103 protected RouterDpnChangeListener getDataTreeChangeListener() {
104 return RouterDpnChangeListener.this;
108 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
109 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
110 .child(DpnVpninterfacesList.class);
114 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
115 LOG.trace("add : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
116 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
117 BigInteger dpnId = dpnInfo.getDpnId();
118 //check router is associated to external network
119 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
120 Optional<Routers> routerData =
121 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
122 LogicalDatastoreType.CONFIGURATION, id);
123 if (routerData.isPresent()) {
124 Routers router = routerData.get();
125 Uuid networkId = router.getNetworkId();
126 if (networkId != null) {
127 if (natMode == NatMode.Conntrack) {
128 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
129 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
130 LOG.warn("add : NAPT switch is not selected.");
133 //If it is for NAPT switch skip as the flows would be already programmed.
134 if (naptSwitch.equals(dpnId)) {
135 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
138 natServiceManager.notify(router, naptSwitch, dpnId,
139 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
141 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + dpnInfo.getKey(), () -> {
142 List<ListenableFuture<Void>> futures = new ArrayList<>(2);
143 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
144 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
145 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
146 if (routerId == NatConstants.INVALID_ID) {
147 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
150 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
151 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(writeFlowInvTx -> {
153 if (vpnName == null) {
154 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
156 if (vpnId == NatConstants.INVALID_ID) {
157 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
160 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
161 //Install default entry in FIB to SNAT table
162 LOG.info("add : Installing default route in FIB on dpn {} for router {} with vpn {}",
163 dpnId, routerUuid, vpnId);
164 installDefaultNatRouteForRouterExternalSubnets(dpnId,
165 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
166 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, writeFlowInvTx);
168 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
169 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
170 if (vpnId == NatConstants.INVALID_ID) {
171 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
175 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
176 //Install default entry in FIB to SNAT table
177 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
178 + "vpnId {}...", dpnId, routerUuid, vpnId);
179 installDefaultNatRouteForRouterExternalSubnets(dpnId,
180 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
181 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId,
185 if (router.isEnableSnat()) {
186 LOG.info("add : SNAT enabled for router {}", routerUuid);
187 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
188 routerUuid, networkId);
189 if (extNwProvType == null) {
190 LOG.error("add : External Network Provider Type missing");
193 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(removeFlowInvTx -> {
194 handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, writeFlowInvTx,
195 removeFlowInvTx, extNwProvType);
198 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
203 }, NatConstants.NAT_DJC_MAX_RETRIES);
204 } // end of controller based SNAT
207 LOG.debug("add : Router {} is not associated with External network", routerUuid);
212 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
213 LOG.trace("remove : key: {}, value: {}", dpnInfo.getKey(), 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);
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.");
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);
241 natServiceManager.notify(router, naptSwitch, dpnId,
242 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
244 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + dpnInfo.getKey(), () -> {
245 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
246 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
247 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
249 if (vpnName == null) {
250 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
252 if (vpnId == NatConstants.INVALID_ID) {
253 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
256 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
257 //Remove default entry in FIB
258 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
260 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, tx);
262 LOG.debug("remove : External vpn associated to router {}", routerUuid);
263 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
264 if (vpnId == NatConstants.INVALID_ID) {
265 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
268 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
269 //Remove default entry in FIB
270 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
272 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, tx);
275 if (router.isEnableSnat()) {
276 LOG.info("remove : SNAT enabled for router {}", routerUuid);
277 removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, tx);
279 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
283 }, NatConstants.NAT_DJC_MAX_RETRIES);
284 } // end of controller based SNAT
290 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
291 DpnVpninterfacesList update) {
292 LOG.trace("Update key: {}, original: {}, update: {}", update.getKey(), original, update);
295 // TODO Clean up the exception handling
296 @SuppressWarnings("checkstyle:IllegalCatch")
297 void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
298 WriteTransaction writeFlowInvTx, WriteTransaction removeFlowInvTx, ProviderTypes extNwProvType) {
299 //Check if primary and secondary switch are selected, If not select the role
300 //Install select group to NAPT switch
301 //Install default miss entry to NAPT switch
302 BigInteger naptSwitch;
304 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
305 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
306 LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
308 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
310 LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
311 naptSwitch, routerName);
314 LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
316 // When NAPT switch is elected during first VM comes up for the given Router
317 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
318 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
319 idManager, NatConstants.ODL_VNI_POOL_NAME);
322 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
323 if (extRouters != null) {
324 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
325 naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
328 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
330 // Install miss entry (table 26) pointing to table 46
331 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
332 routerVpnId, NatConstants.ADD_FLOW);
333 if (flowEntity == null) {
334 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
338 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
339 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
340 //Removing primary flows from old napt switch
341 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
342 LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
344 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptId, null, removeFlowInvTx);
346 } else if (naptId.equals(dpnId)) {
347 LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
350 LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
354 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
355 routerName, routerId, naptSwitch);
356 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
358 // Install miss entry (table 26) pointing to group
359 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
360 FlowEntity flowEntity =
361 naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
362 routerVpnId, NatConstants.ADD_FLOW);
363 if (flowEntity == null) {
364 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
365 routerName, dpnId, groupId);
368 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
369 dpnId, routerName, groupId);
370 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
373 } catch (Exception ex) {
374 LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
378 // TODO Clean up the exception handling
379 @SuppressWarnings("checkstyle:IllegalCatch")
380 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
381 Uuid extNetworkId, WriteTransaction removeFlowInvTx) {
382 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
383 //remove miss entry to NAPT switch
384 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
386 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
387 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
388 if (extNwProvType == null) {
391 //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
392 Map<String, Long> externalIpLabel;
393 if (extNwProvType == ProviderTypes.VXLAN) {
394 externalIpLabel = null;
396 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
398 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
399 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
400 LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
405 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
406 externalIpCache, removeFlowInvTx);
408 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
410 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
411 FlowEntity flowEntity = null;
413 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
414 NatConstants.DEL_FLOW);
415 if (flowEntity == null) {
416 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
417 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
420 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
421 mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
423 } catch (Exception ex) {
424 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
428 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
432 GroupEntity groupEntity = null;
434 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
435 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
436 LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
437 mdsalManager.removeGroup(groupEntity);
438 } catch (Exception ex) {
439 LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
442 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
445 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
446 externalIpLabel, removeFlowInvTx);
447 //remove table 26 flow ppointing to table46
448 FlowEntity flowEntity = null;
450 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
451 NatConstants.DEL_FLOW);
452 if (flowEntity == null) {
453 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
457 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
458 + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
459 mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
461 } catch (Exception ex) {
462 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
466 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
469 //best effort to check IntExt model
470 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, removeFlowInvTx);
472 } catch (Exception ex) {
473 LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
477 private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
478 if (externalSubnetIds == null) {
479 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
483 for (Uuid subnetId : externalSubnetIds) {
484 long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
485 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
486 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
487 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
488 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
490 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);