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 java.util.Collection;
13 import java.util.Collections;
14 import java.util.Optional;
15 import javax.annotation.PreDestroy;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
19 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
21 import org.opendaylight.genius.mdsalutil.NwConstants;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
23 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
24 import org.opendaylight.infrautils.utils.concurrent.Executors;
25 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
26 import org.opendaylight.mdsal.binding.api.DataBroker;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
28 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
29 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
30 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
31 import org.opendaylight.serviceutils.upgrade.UpgradeState;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.opendaylight.yangtools.yang.common.Uint32;
43 import org.opendaylight.yangtools.yang.common.Uint64;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 public class RouterDpnChangeListener extends AbstractAsyncDataTreeChangeListener<DpnVpninterfacesList> {
50 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
51 private final DataBroker dataBroker;
52 private final ManagedNewTransactionRunner txRunner;
53 private final IMdsalApiManager mdsalManager;
54 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
55 private final NaptSwitchHA naptSwitchHA;
56 private final IdManagerService idManager;
57 private final INeutronVpnManager nvpnManager;
58 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
59 private final JobCoordinator coordinator;
60 private final SnatServiceManager natServiceManager;
61 private final NatMode natMode;
62 private final UpgradeState upgradeState;
65 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
66 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
67 final NaptSwitchHA naptSwitchHA,
68 final IdManagerService idManager,
69 final ExternalNetworkGroupInstaller extNetGroupInstaller,
70 final INeutronVpnManager nvpnManager,
71 final SnatServiceManager natServiceManager,
72 final NatserviceConfig config,
73 final JobCoordinator coordinator,
74 final UpgradeState upgradeState) {
75 super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NeutronRouterDpns.class)
76 .child(RouterDpnList.class).child(DpnVpninterfacesList.class),
77 Executors.newListeningSingleThreadExecutor("RouterDpnChangeListener", LOG));
78 this.dataBroker = dataBroker;
79 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
80 this.mdsalManager = mdsalManager;
81 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
82 this.naptSwitchHA = naptSwitchHA;
83 this.idManager = idManager;
84 this.extNetGroupInstaller = extNetGroupInstaller;
85 this.nvpnManager = nvpnManager;
86 this.natServiceManager = natServiceManager;
87 this.coordinator = coordinator;
88 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
89 this.upgradeState = upgradeState;
93 LOG.info("{} init", getClass().getSimpleName());
100 Executors.shutdownAndAwaitTermination(getExecutorService());
104 public void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
105 LOG.trace("add : key: {}, value: {}", dpnInfo.key(), dpnInfo);
106 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
107 Uint64 dpnId = dpnInfo.getDpnId();
108 //check router is associated to external network
109 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
110 Optional<Routers> routerData =
111 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
112 LogicalDatastoreType.CONFIGURATION, id);
113 if (routerData.isPresent()) {
114 Routers router = routerData.get();
115 Uuid networkId = router.getNetworkId();
116 if (networkId != null) {
117 if (natMode == NatMode.Conntrack) {
118 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
119 if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
120 LOG.warn("add : NAPT switch is not selected.");
123 //If it is for NAPT switch skip as the flows would be already programmed.
124 if (naptSwitch.equals(dpnId)) {
125 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
128 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
130 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
131 SnatServiceManager.Action.CNT_ROUTER_ENBL);
132 if (router.isEnableSnat()) {
133 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
134 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
136 }), LOG, "Error notifying NAT service manager");
138 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
139 if (routerId == NatConstants.INVALID_ID) {
140 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
143 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
144 routerUuid, networkId);
145 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
146 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
147 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
148 installDefaultNatRouteForRouterExternalSubnets(dpnId,
149 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
150 return Collections.emptyList();
153 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
154 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
155 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
156 return Collections.singletonList(
157 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
159 if (vpnName == null) {
160 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
162 if (vpnId == NatConstants.INVALID_ID) {
163 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
166 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
167 //Install default entry in FIB to SNAT table
169 "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
170 dpnId, routerUuid, vpnId);
171 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
173 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
174 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
175 if (vpnId == NatConstants.INVALID_ID) {
176 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
179 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
180 //Install default entry in FIB to SNAT table
181 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
182 + "vpnId {}...", dpnId, routerUuid, vpnId);
183 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
185 /* install V6 internet default fallback rule in FIB_TABLE if router
186 * is having V6 subnet
188 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
189 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.ADD_FLOW);
190 if (router.isEnableSnat()) {
191 LOG.info("add : SNAT enabled for router {}", routerUuid);
192 if (extNwProvType == null) {
193 LOG.error("add : External Network Provider Type missing");
196 NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
197 dpnId, router, routerId, vpnId, confTx, extNwProvType, upgradeState);
199 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 public void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
213 LOG.trace("remove : key: {}, value: {}", dpnInfo.key(), dpnInfo);
214 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
215 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
216 if (routerId == NatConstants.INVALID_ID) {
217 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
220 Uint64 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 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
232 if (naptSwitch == null || naptSwitch.equals(Uint64.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 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
243 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
244 SnatServiceManager.Action.CNT_ROUTER_DISBL);
245 if (router.isEnableSnat()) {
246 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
247 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
249 }), LOG, "Error notifying NAT service manager");
251 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
252 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
253 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
254 return Collections.singletonList(
255 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
257 if (vpnName == null) {
258 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
260 if (vpnId == NatConstants.INVALID_ID) {
261 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
264 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
265 //Remove default entry in FIB
266 LOG.debug("remove : Removing default route in FIB on dpn {} ...", 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);
281 /* remove V6 internet default fallback rule in FIB_TABLE if router
282 * is having V6 subnet
284 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
285 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.DEL_FLOW);
286 if (router.isEnableSnat()) {
287 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
288 routerUuid, networkId);
289 if (extNwProvType == null) {
292 LOG.info("remove : SNAT enabled for router {}", routerUuid);
293 String externalVpnName = NatUtil.getAssociatedVPN(dataBroker,
294 routerData.get().getNetworkId());
295 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, dpnId,
296 router, routerId, vpnId, externalVpnName, extNwProvType, confTx);
298 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
302 }, NatConstants.NAT_DJC_MAX_RETRIES);
303 } // end of controller based SNAT
309 public void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
310 DpnVpninterfacesList update) {
311 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
314 private void installDefaultNatRouteForRouterExternalSubnets(Uint64 dpnId, Collection<Uuid> externalSubnetIds) {
315 if (externalSubnetIds == null) {
316 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
320 for (Uuid subnetId : externalSubnetIds) {
321 Uint32 vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
322 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
323 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
324 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
325 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
327 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);