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.serviceutils.upgrade.UpgradeState;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 public class RouterDpnChangeListener
57 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
59 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
60 private final DataBroker dataBroker;
61 private final ManagedNewTransactionRunner txRunner;
62 private final IMdsalApiManager mdsalManager;
63 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
64 private final NaptSwitchHA naptSwitchHA;
65 private final IdManagerService idManager;
66 private final INeutronVpnManager nvpnManager;
67 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
68 private final IElanService elanManager;
69 private final JobCoordinator coordinator;
70 private final SnatServiceManager natServiceManager;
71 private final NatMode natMode;
72 private final UpgradeState upgradeState;
75 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
76 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
77 final NaptSwitchHA naptSwitchHA,
78 final IdManagerService idManager,
79 final ExternalNetworkGroupInstaller extNetGroupInstaller,
80 final INeutronVpnManager nvpnManager,
81 final SnatServiceManager natServiceManager,
82 final NatserviceConfig config,
83 final IElanService elanManager,
84 final JobCoordinator coordinator,
85 final UpgradeState upgradeState) {
86 super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
87 this.dataBroker = dataBroker;
88 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
89 this.mdsalManager = mdsalManager;
90 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
91 this.naptSwitchHA = naptSwitchHA;
92 this.idManager = idManager;
93 this.extNetGroupInstaller = extNetGroupInstaller;
94 this.nvpnManager = nvpnManager;
95 this.elanManager = elanManager;
96 this.natServiceManager = natServiceManager;
97 this.coordinator = coordinator;
98 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
99 this.upgradeState = upgradeState;
105 LOG.info("{} init", getClass().getSimpleName());
106 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
110 protected RouterDpnChangeListener getDataTreeChangeListener() {
111 return RouterDpnChangeListener.this;
115 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
116 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
117 .child(DpnVpninterfacesList.class);
121 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
122 LOG.trace("add : key: {}, value: {}", dpnInfo.key(), dpnInfo);
123 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
124 BigInteger dpnId = dpnInfo.getDpnId();
125 //check router is associated to external network
126 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
127 Optional<Routers> routerData =
128 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
129 LogicalDatastoreType.CONFIGURATION, id);
130 if (routerData.isPresent()) {
131 Routers router = routerData.get();
132 Uuid networkId = router.getNetworkId();
133 if (networkId != null) {
134 if (natMode == NatMode.Conntrack) {
135 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
136 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
137 LOG.warn("add : NAPT switch is not selected.");
140 //If it is for NAPT switch skip as the flows would be already programmed.
141 if (naptSwitch.equals(dpnId)) {
142 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
145 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
146 confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
147 SnatServiceManager.Action.SNAT_ROUTER_ENBL)), LOG, "Error notifying NAT service manager");
149 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
150 if (routerId == NatConstants.INVALID_ID) {
151 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
154 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
155 routerUuid, networkId);
156 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
157 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
158 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
159 installDefaultNatRouteForRouterExternalSubnets(dpnId,
160 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
161 return Collections.emptyList();
164 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
165 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
166 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
167 return Collections.singletonList(
168 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
170 if (vpnName == null) {
171 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
173 if (vpnId == NatConstants.INVALID_ID) {
174 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
177 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
178 //Install default entry in FIB to SNAT table
180 "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
181 dpnId, routerUuid, vpnId);
182 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
184 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
185 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
186 if (vpnId == NatConstants.INVALID_ID) {
187 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
190 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
191 //Install default entry in FIB to SNAT table
192 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
193 + "vpnId {}...", dpnId, routerUuid, vpnId);
194 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
196 if (router.isEnableSnat()) {
197 LOG.info("add : SNAT enabled for router {}", routerUuid);
198 if (extNwProvType == null) {
199 LOG.error("add : External Network Provider Type missing");
202 handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, confTx, extNwProvType);
204 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
208 }, NatConstants.NAT_DJC_MAX_RETRIES);
209 } // end of controller based SNAT
212 LOG.debug("add : Router {} is not associated with External network", routerUuid);
217 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
218 LOG.trace("remove : key: {}, value: {}", dpnInfo.key(), dpnInfo);
219 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
220 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
221 if (routerId == NatConstants.INVALID_ID) {
222 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
225 BigInteger dpnId = dpnInfo.getDpnId();
226 //check router is associated to external network
227 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
228 Optional<Routers> routerData =
229 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
230 LogicalDatastoreType.CONFIGURATION, id);
231 if (routerData.isPresent()) {
232 Routers router = routerData.get();
233 Uuid networkId = router.getNetworkId();
234 if (networkId != null) {
235 if (natMode == NatMode.Conntrack) {
236 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
237 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
238 LOG.warn("remove : NAPT switch is not selected.");
241 //If it is for NAPT switch skip as the flows would be already programmed.
242 if (naptSwitch.equals(dpnId)) {
243 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
246 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
247 confTx -> natServiceManager.notify(confTx, router, naptSwitch, dpnId,
248 SnatServiceManager.Action.SNAT_ROUTER_DISBL)), LOG, "Error notifying NAT service manager");
250 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
251 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
252 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
253 return Collections.singletonList(
254 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
256 if (vpnName == null) {
257 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
259 if (vpnId == NatConstants.INVALID_ID) {
260 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
263 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
264 //Remove default entry in FIB
265 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
267 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, confTx);
269 LOG.debug("remove : External vpn associated to router {}", routerUuid);
270 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
271 if (vpnId == NatConstants.INVALID_ID) {
272 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
275 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
276 //Remove default entry in FIB
277 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
279 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, 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 void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
303 TypedReadWriteTransaction<Configuration> confTx, ProviderTypes extNwProvType) {
304 //Check if primary and secondary switch are selected, If not select the role
305 //Install select group to NAPT switch
306 //Install default miss entry to NAPT switch
307 BigInteger naptSwitch;
309 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
310 if (naptId == null || naptId.equals(BigInteger.ZERO)
311 || !NatUtil.getSwitchStatus(dataBroker, naptId) && !upgradeState.isUpgradeInProgress()) {
312 LOG.debug("handleSNATForDPN : NaptSwitch is down or not selected for router {},naptId {}",
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 (InterruptedException | ExecutionException e) {
381 LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", e);
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 (InterruptedException | ExecutionException e) {
480 LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, e);
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);