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.key(), 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 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
142 if (routerId == NatConstants.INVALID_ID) {
143 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
146 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
147 routerUuid, networkId);
148 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
149 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
150 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
151 installDefaultNatRouteForRouterExternalSubnets(dpnId,
152 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
153 return Collections.emptyList();
156 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
157 List<ListenableFuture<Void>> futures = new ArrayList<>(2);
158 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
159 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
160 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(writeFlowInvTx -> {
162 if (vpnName == null) {
163 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
165 if (vpnId == NatConstants.INVALID_ID) {
166 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
169 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
170 //Install default entry in FIB to SNAT table
171 LOG.info("add : Installing default route in FIB on dpn {} for router {} with vpn {}",
172 dpnId, routerUuid, vpnId);
173 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, writeFlowInvTx);
175 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
176 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
177 if (vpnId == NatConstants.INVALID_ID) {
178 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
181 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
182 //Install default entry in FIB to SNAT table
183 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
184 + "vpnId {}...", dpnId, routerUuid, vpnId);
185 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId,
188 if (router.isEnableSnat()) {
189 LOG.info("add : SNAT enabled for router {}", routerUuid);
190 if (extNwProvType == null) {
191 LOG.error("add : External Network Provider Type missing");
194 futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(removeFlowInvTx -> {
195 handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, writeFlowInvTx,
196 removeFlowInvTx, extNwProvType);
199 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 natServiceManager.notify(router, naptSwitch, dpnId,
243 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
245 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
246 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
247 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
248 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
250 if (vpnName == null) {
251 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
253 if (vpnId == NatConstants.INVALID_ID) {
254 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
257 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
258 //Remove default entry in FIB
259 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
261 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, tx);
263 LOG.debug("remove : External vpn associated to router {}", routerUuid);
264 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
265 if (vpnId == NatConstants.INVALID_ID) {
266 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
269 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
270 //Remove default entry in FIB
271 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
273 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, tx);
276 if (router.isEnableSnat()) {
277 LOG.info("remove : SNAT enabled for router {}", routerUuid);
278 removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, tx);
280 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
284 }, NatConstants.NAT_DJC_MAX_RETRIES);
285 } // end of controller based SNAT
291 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
292 DpnVpninterfacesList update) {
293 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
296 // TODO Clean up the exception handling
297 @SuppressWarnings("checkstyle:IllegalCatch")
298 void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
299 WriteTransaction writeFlowInvTx, WriteTransaction removeFlowInvTx, 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, writeFlowInvTx);
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.addFlowToTx(flowEntity, writeFlowInvTx);
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, removeFlowInvTx);
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.addFlowToTx(flowEntity, writeFlowInvTx);
374 } catch (Exception ex) {
375 LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
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, WriteTransaction removeFlowInvTx) {
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, removeFlowInvTx);
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.removeFlowToTx(flowEntity, removeFlowInvTx);
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, removeFlowInvTx);
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.removeFlowToTx(flowEntity, removeFlowInvTx);
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, removeFlowInvTx);
473 } catch (Exception ex) {
474 LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
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);