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 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.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
25 import org.opendaylight.genius.infra.Datastore.Configuration;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
28 import org.opendaylight.genius.infra.TransactionAdapter;
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,
179 TransactionAdapter.toWriteTransaction(confTx));
181 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
182 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
183 if (vpnId == NatConstants.INVALID_ID) {
184 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
187 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
188 //Install default entry in FIB to SNAT table
189 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
190 + "vpnId {}...", dpnId, routerUuid, vpnId);
191 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId,
192 TransactionAdapter.toWriteTransaction(confTx));
194 if (router.isEnableSnat()) {
195 LOG.info("add : SNAT enabled for router {}", routerUuid);
196 if (extNwProvType == null) {
197 LOG.error("add : External Network Provider Type missing");
200 handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, confTx, extNwProvType);
202 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
206 }, NatConstants.NAT_DJC_MAX_RETRIES);
207 } // end of controller based SNAT
210 LOG.debug("add : Router {} is not associated with External network", routerUuid);
215 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
216 LOG.trace("remove : key: {}, value: {}", dpnInfo.key(), dpnInfo);
217 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
218 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
219 if (routerId == NatConstants.INVALID_ID) {
220 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
223 BigInteger dpnId = dpnInfo.getDpnId();
224 //check router is associated to external network
225 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
226 Optional<Routers> routerData =
227 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
228 LogicalDatastoreType.CONFIGURATION, id);
229 if (routerData.isPresent()) {
230 Routers router = routerData.get();
231 Uuid networkId = router.getNetworkId();
232 if (networkId != null) {
233 if (natMode == NatMode.Conntrack) {
234 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
235 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
236 LOG.warn("remove : NAPT switch is not selected.");
239 //If it is for NAPT switch skip as the flows would be already programmed.
240 if (naptSwitch.equals(dpnId)) {
241 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
244 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
245 confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
246 SnatServiceManager.Action.SNAT_ROUTER_DISBL)), LOG, "Error notifying NAT service manager");
248 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
249 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
250 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
251 return Collections.singletonList(
252 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
254 if (vpnName == null) {
255 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
257 if (vpnId == NatConstants.INVALID_ID) {
258 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
261 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
262 //Remove default entry in FIB
263 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
265 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId,
266 TransactionAdapter.toWriteTransaction(confTx));
268 LOG.debug("remove : External vpn associated to router {}", routerUuid);
269 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
270 if (vpnId == NatConstants.INVALID_ID) {
271 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
274 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
275 //Remove default entry in FIB
276 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
278 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId,
279 TransactionAdapter.toWriteTransaction(confTx));
282 if (router.isEnableSnat()) {
283 LOG.info("remove : SNAT enabled for router {}", routerUuid);
284 removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, confTx);
286 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
290 }, NatConstants.NAT_DJC_MAX_RETRIES);
291 } // end of controller based SNAT
297 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
298 DpnVpninterfacesList update) {
299 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
302 // TODO Clean up the exception handling
303 @SuppressWarnings("checkstyle:IllegalCatch")
304 void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
305 TypedReadWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
306 //Check if primary and secondary switch are selected, If not select the role
307 //Install select group to NAPT switch
308 //Install default miss entry to NAPT switch
309 BigInteger naptSwitch;
311 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
312 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
313 LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
315 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
317 LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
318 naptSwitch, routerName);
321 LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
323 // When NAPT switch is elected during first VM comes up for the given Router
324 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
325 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
326 idManager, NatConstants.ODL_VNI_POOL_NAME);
329 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
330 if (extRouters != null) {
331 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
332 naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
335 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, confTx);
337 // Install miss entry (table 26) pointing to table 46
338 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
339 routerVpnId, NatConstants.ADD_FLOW);
340 if (flowEntity == null) {
341 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
345 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
346 mdsalManager.addFlow(confTx, flowEntity);
347 //Removing primary flows from old napt switch
348 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
349 LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
351 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptId, null, confTx);
353 } else if (naptId.equals(dpnId)) {
354 LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
357 LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
361 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
362 routerName, routerId, naptSwitch);
363 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
365 // Install miss entry (table 26) pointing to group
366 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
367 FlowEntity flowEntity =
368 naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
369 routerVpnId, NatConstants.ADD_FLOW);
370 if (flowEntity == null) {
371 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
372 routerName, dpnId, groupId);
375 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
376 dpnId, routerName, groupId);
377 mdsalManager.addFlow(confTx, flowEntity);
380 } catch (Exception ex) {
381 LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
385 // TODO Clean up the exception handling
386 @SuppressWarnings("checkstyle:IllegalCatch")
387 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
388 Uuid extNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
389 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
390 //remove miss entry to NAPT switch
391 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
393 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
394 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
395 if (extNwProvType == null) {
398 //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
399 Map<String, Long> externalIpLabel;
400 if (extNwProvType == ProviderTypes.VXLAN) {
401 externalIpLabel = null;
403 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
405 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
406 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
407 LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
412 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
413 externalIpCache, confTx);
415 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
417 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
418 FlowEntity flowEntity = null;
420 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
421 NatConstants.DEL_FLOW);
422 if (flowEntity == null) {
423 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
424 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
427 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
428 mdsalManager.removeFlow(confTx, flowEntity);
430 } catch (Exception ex) {
431 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
435 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
439 GroupEntity groupEntity = null;
441 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
442 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
443 LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
444 mdsalManager.removeGroup(groupEntity);
445 } catch (Exception ex) {
446 LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
449 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
452 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
453 externalIpLabel, confTx);
454 //remove table 26 flow ppointing to table46
455 FlowEntity flowEntity = null;
457 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
458 NatConstants.DEL_FLOW);
459 if (flowEntity == null) {
460 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
464 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
465 + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
466 mdsalManager.removeFlow(confTx, flowEntity);
468 } catch (Exception ex) {
469 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
473 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
476 //best effort to check IntExt model
477 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, confTx);
479 } catch (Exception ex) {
480 LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
484 private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
485 if (externalSubnetIds == null) {
486 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
490 for (Uuid subnetId : externalSubnetIds) {
491 long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
492 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
493 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
494 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
495 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
497 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);