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.mdsalutil.BucketInfo;
27 import org.opendaylight.genius.mdsalutil.FlowEntity;
28 import org.opendaylight.genius.mdsalutil.GroupEntity;
29 import org.opendaylight.genius.mdsalutil.MDSALUtil;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
32 import org.opendaylight.netvirt.elanmanager.api.IElanService;
33 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
34 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 public class RouterDpnChangeListener
51 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
53 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
54 private final DataBroker dataBroker;
55 private final IMdsalApiManager mdsalManager;
56 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
57 private final NaptSwitchHA naptSwitchHA;
58 private final IdManagerService idManager;
59 private final INeutronVpnManager nvpnManager;
60 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
61 private final IElanService elanManager;
62 private final JobCoordinator coordinator;
63 private final SnatServiceManager natServiceManager;
64 private final NatMode natMode;
67 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
68 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
69 final NaptSwitchHA naptSwitchHA,
70 final IdManagerService idManager,
71 final ExternalNetworkGroupInstaller extNetGroupInstaller,
72 final INeutronVpnManager nvpnManager,
73 final SnatServiceManager natServiceManager,
74 final NatserviceConfig config,
75 final IElanService elanManager,
76 final JobCoordinator coordinator) {
77 super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
78 this.dataBroker = dataBroker;
79 this.mdsalManager = mdsalManager;
80 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
81 this.naptSwitchHA = naptSwitchHA;
82 this.idManager = idManager;
83 this.extNetGroupInstaller = extNetGroupInstaller;
84 this.nvpnManager = nvpnManager;
85 this.elanManager = elanManager;
86 this.natServiceManager = natServiceManager;
87 this.coordinator = coordinator;
88 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
94 LOG.info("{} init", getClass().getSimpleName());
95 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
99 protected RouterDpnChangeListener getDataTreeChangeListener() {
100 return RouterDpnChangeListener.this;
104 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
105 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
106 .child(DpnVpninterfacesList.class);
110 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
111 LOG.trace("add : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
112 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
113 BigInteger dpnId = dpnInfo.getDpnId();
114 //check router is associated to external network
115 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
116 Optional<Routers> routerData =
117 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
118 LogicalDatastoreType.CONFIGURATION, id);
119 if (routerData.isPresent()) {
120 Routers router = routerData.get();
121 Uuid networkId = router.getNetworkId();
122 if (networkId != null) {
123 if (natMode == NatMode.Conntrack) {
124 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
125 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
126 LOG.warn("add : NAPT switch is not selected.");
129 //If it is for NAPT switch skip as the flows would be already programmed.
130 if (naptSwitch.equals(dpnId)) {
131 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
134 natServiceManager.notify(router, naptSwitch, dpnId,
135 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
137 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + dpnInfo.getKey(), () -> {
138 WriteTransaction writeFlowInvTx = dataBroker.newWriteOnlyTransaction();
139 WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
140 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
141 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
142 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
143 List<ListenableFuture<Void>> futures = new ArrayList<>();
144 if (routerId == NatConstants.INVALID_ID) {
145 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
146 writeFlowInvTx.cancel();
147 removeFlowInvTx.cancel();
150 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
152 if (vpnName == null) {
153 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
155 if (vpnId == NatConstants.INVALID_ID) {
156 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
157 writeFlowInvTx.cancel();
158 removeFlowInvTx.cancel();
161 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
162 //Install default entry in FIB to SNAT table
163 LOG.info("add : Installing default route in FIB on dpn {} for router {} with vpn {}",
164 dpnId, routerUuid, vpnId);
165 installDefaultNatRouteForRouterExternalSubnets(dpnId,
166 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
167 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, writeFlowInvTx);
169 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
170 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
171 if (vpnId == NatConstants.INVALID_ID) {
172 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
173 writeFlowInvTx.cancel();
174 removeFlowInvTx.cancel();
178 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
179 //Install default entry in FIB to SNAT table
180 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
181 + "vpnId {}...", dpnId, routerUuid, vpnId);
182 installDefaultNatRouteForRouterExternalSubnets(dpnId,
183 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
184 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, writeFlowInvTx);
188 if (router.isEnableSnat()) {
189 LOG.info("add : SNAT enabled for router {}", routerUuid);
190 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
191 routerUuid, networkId);
192 if (extNwProvType == null) {
193 LOG.error("add : External Network Provider Type missing");
194 writeFlowInvTx.cancel();
195 removeFlowInvTx.cancel();
198 handleSNATForDPN(dpnId, routerUuid, routerId, vpnId, writeFlowInvTx, removeFlowInvTx,
201 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
204 futures.add(NatUtil.waitForTransactionToComplete(writeFlowInvTx));
205 futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
207 }, NatConstants.NAT_DJC_MAX_RETRIES);
208 } // end of controller based SNAT
211 LOG.debug("add : Router {} is not associated with External network", routerUuid);
216 protected void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
217 LOG.trace("remove : key: {}, value: {}", dpnInfo.getKey(), dpnInfo);
218 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
219 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
220 if (routerId == NatConstants.INVALID_ID) {
221 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
224 BigInteger dpnId = dpnInfo.getDpnId();
225 //check router is associated to external network
226 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
227 Optional<Routers> routerData =
228 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
229 LogicalDatastoreType.CONFIGURATION, id);
230 if (routerData.isPresent()) {
231 Routers router = routerData.get();
232 Uuid networkId = router.getNetworkId();
233 if (networkId != null) {
234 if (natMode == NatMode.Conntrack) {
235 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
236 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
237 LOG.warn("remove : NAPT switch is not selected.");
240 //If it is for NAPT switch skip as the flows would be already programmed.
241 if (naptSwitch.equals(dpnId)) {
242 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
245 natServiceManager.notify(router, naptSwitch, dpnId,
246 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
248 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + dpnInfo.getKey(), () -> {
249 WriteTransaction removeFlowInvTx = dataBroker.newWriteOnlyTransaction();
250 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
251 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
253 List<ListenableFuture<Void>> futures = new ArrayList<>();
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);
259 removeFlowInvTx.cancel();
262 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
263 //Remove default entry in FIB
264 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
266 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, removeFlowInvTx);
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);
272 removeFlowInvTx.cancel();
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, removeFlowInvTx);
282 if (router.isEnableSnat()) {
283 LOG.info("remove : SNAT enabled for router {}", routerUuid);
284 removeSNATFromDPN(dpnId, routerUuid, routerId, vpnId, networkId, removeFlowInvTx);
286 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
289 futures.add(NatUtil.waitForTransactionToComplete(removeFlowInvTx));
291 }, NatConstants.NAT_DJC_MAX_RETRIES);
292 } // end of controller based SNAT
298 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
299 DpnVpninterfacesList update) {
300 LOG.trace("Update key: {}, original: {}, update: {}", update.getKey(), original, update);
303 // TODO Clean up the exception handling
304 @SuppressWarnings("checkstyle:IllegalCatch")
305 void handleSNATForDPN(BigInteger dpnId, String routerName, long routerId, Long routerVpnId,
306 WriteTransaction writeFlowInvTx, WriteTransaction removeFlowInvTx, ProviderTypes extNwProvType) {
307 //Check if primary and secondary switch are selected, If not select the role
308 //Install select group to NAPT switch
309 //Install default miss entry to NAPT switch
310 BigInteger naptSwitch;
312 BigInteger naptId = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
313 if (naptId == null || naptId.equals(BigInteger.ZERO) || !naptSwitchHA.getSwitchStatus(naptId)) {
314 LOG.debug("handleSNATForDPN : No NaptSwitch is selected for router {}", routerName);
316 boolean naptstatus = naptSwitchHA.updateNaptSwitch(routerName, naptSwitch);
318 LOG.error("handleSNATForDPN : Failed to update newNaptSwitch {} for routername {}",
319 naptSwitch, routerName);
322 LOG.debug("handleSNATForDPN : Switch {} is elected as NaptSwitch for router {}", dpnId, routerName);
324 // When NAPT switch is elected during first VM comes up for the given Router
325 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanManager, extNwProvType)) {
326 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager,
327 idManager, NatConstants.ODL_VNI_POOL_NAME);
330 Routers extRouters = NatUtil.getRoutersFromConfigDS(dataBroker, routerName);
331 if (extRouters != null) {
332 NatUtil.createRouterIdsConfigDS(dataBroker, routerId, routerName);
333 naptSwitchHA.subnetRegisterMapping(extRouters, routerId);
336 naptSwitchHA.installSnatFlows(routerName, routerId, naptSwitch, routerVpnId, writeFlowInvTx);
338 // Install miss entry (table 26) pointing to table 46
339 FlowEntity flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName,
340 routerVpnId, NatConstants.ADD_FLOW);
341 if (flowEntity == null) {
342 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {}",
346 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {}", dpnId, routerName);
347 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
348 //Removing primary flows from old napt switch
349 if (naptId != null && !naptId.equals(BigInteger.ZERO)) {
350 LOG.debug("handleSNATForDPN : Removing primary flows from old napt switch {} for router {}",
352 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptId, null, removeFlowInvTx);
354 } else if (naptId.equals(dpnId)) {
355 LOG.debug("handleSNATForDPN : NaptSwitch {} gone down during cluster reboot came alive", naptId);
358 LOG.debug("handleSNATForDPN : Napt switch with Id {} is already elected for router {}",
362 List<BucketInfo> bucketInfo = naptSwitchHA.handleGroupInNeighborSwitches(dpnId,
363 routerName, routerId, naptSwitch);
364 naptSwitchHA.installSnatGroupEntry(dpnId, bucketInfo, routerName);
366 // Install miss entry (table 26) pointing to group
367 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
368 FlowEntity flowEntity =
369 naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId,
370 routerVpnId, NatConstants.ADD_FLOW);
371 if (flowEntity == null) {
372 LOG.error("handleSNATForDPN : Failed to populate flowentity for router {} with dpnId {} groupId {}",
373 routerName, dpnId, groupId);
376 LOG.debug("handleSNATForDPN : Successfully installed flow for dpnId {} router {} group {}",
377 dpnId, routerName, groupId);
378 mdsalManager.addFlowToTx(flowEntity, writeFlowInvTx);
381 } catch (Exception ex) {
382 LOG.error("handleSNATForDPN : Exception in handleSNATForDPN", ex);
386 // TODO Clean up the exception handling
387 @SuppressWarnings("checkstyle:IllegalCatch")
388 void removeSNATFromDPN(BigInteger dpnId, String routerName, long routerId, long routerVpnId,
389 Uuid extNetworkId, WriteTransaction removeFlowInvTx) {
390 //irrespective of naptswitch or non-naptswitch, SNAT default miss entry need to be removed
391 //remove miss entry to NAPT switch
392 //if naptswitch elect new switch and install Snat flows and remove those flows in oldnaptswitch
394 Collection<String> externalIpCache = NatUtil.getExternalIpsForRouter(dataBroker, routerId);
395 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNetworkId);
396 if (extNwProvType == null) {
399 //Get the external IP labels other than VXLAN provider type. Since label is not applicable for VXLAN
400 Map<String, Long> externalIpLabel;
401 if (extNwProvType == ProviderTypes.VXLAN) {
402 externalIpLabel = null;
404 externalIpLabel = NatUtil.getExternalIpsLabelForRouter(dataBroker, routerId);
406 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, routerName);
407 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
408 LOG.error("removeSNATFromDPN : No naptSwitch is selected for router {}", routerName);
413 naptSwitchHA.isNaptSwitchDown(routerName, routerId, dpnId, naptSwitch, routerVpnId,
414 externalIpCache, removeFlowInvTx);
416 LOG.debug("removeSNATFromDPN: Switch with DpnId {} is not naptSwitch for router {}",
418 long groupId = NatUtil.createGroupId(NatUtil.getGroupIdKey(routerName), idManager);
419 FlowEntity flowEntity = null;
421 flowEntity = naptSwitchHA.buildSnatFlowEntity(dpnId, routerName, groupId, routerVpnId,
422 NatConstants.DEL_FLOW);
423 if (flowEntity == null) {
424 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router:{} "
425 + "with dpnId:{} groupId:{}", routerName, dpnId, groupId);
428 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity {}", flowEntity);
429 mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
431 } catch (Exception ex) {
432 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
436 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
440 GroupEntity groupEntity = null;
442 groupEntity = MDSALUtil.buildGroupEntity(dpnId, groupId, routerName,
443 GroupTypes.GroupAll, Collections.emptyList() /*listBucketInfo*/);
444 LOG.info("removeSNATFromDPN : Removing NAPT GroupEntity:{}", groupEntity);
445 mdsalManager.removeGroup(groupEntity);
446 } catch (Exception ex) {
447 LOG.error("removeSNATFromDPN : Failed to remove group entity {}", groupEntity, ex);
450 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routerName {}",
453 naptSwitchHA.removeSnatFlowsInOldNaptSwitch(routerName, routerId, naptSwitch,
454 externalIpLabel, removeFlowInvTx);
455 //remove table 26 flow ppointing to table46
456 FlowEntity flowEntity = null;
458 flowEntity = naptSwitchHA.buildSnatFlowEntityForNaptSwitch(dpnId, routerName, routerVpnId,
459 NatConstants.DEL_FLOW);
460 if (flowEntity == null) {
461 LOG.error("removeSNATFromDPN : Failed to populate flowentity for router {} with dpnId {}",
465 LOG.debug("removeSNATFromDPN : Removing default SNAT miss entry flow entity for router {} with "
466 + "dpnId {} in napt switch {}", routerName, dpnId, naptSwitch);
467 mdsalManager.removeFlowToTx(flowEntity, removeFlowInvTx);
469 } catch (Exception ex) {
470 LOG.error("removeSNATFromDPN : Failed to remove default SNAT miss entry flow entity {}",
474 LOG.debug("removeSNATFromDPN : Removed default SNAT miss entry flow for dpnID {} with routername {}",
477 //best effort to check IntExt model
478 naptSwitchHA.bestEffortDeletion(routerId, routerName, externalIpLabel, removeFlowInvTx);
480 } catch (Exception ex) {
481 LOG.error("removeSNATFromDPN : Exception while handling naptSwitch down for router {}", routerName, ex);
485 private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
486 if (externalSubnetIds == null) {
487 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
491 for (Uuid subnetId : externalSubnetIds) {
492 long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
493 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
494 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
495 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
496 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
498 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);