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.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.Optional;
16 import javax.annotation.PreDestroy;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
22 import org.opendaylight.genius.mdsalutil.NwConstants;
23 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
25 import org.opendaylight.infrautils.utils.concurrent.Executors;
26 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
27 import org.opendaylight.mdsal.binding.api.DataBroker;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
30 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
31 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
32 import org.opendaylight.serviceutils.upgrade.UpgradeState;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
43 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
44 import org.opendaylight.yangtools.yang.common.Uint32;
45 import org.opendaylight.yangtools.yang.common.Uint64;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 public class RouterDpnChangeListener extends AbstractAsyncDataTreeChangeListener<DpnVpninterfacesList> {
52 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
53 private final DataBroker dataBroker;
54 private final ManagedNewTransactionRunner txRunner;
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 JobCoordinator coordinator;
62 private final SnatServiceManager natServiceManager;
63 private final NatMode natMode;
64 private final UpgradeState upgradeState;
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 JobCoordinator coordinator,
76 final UpgradeState upgradeState) {
77 super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NeutronRouterDpns.class)
78 .child(RouterDpnList.class).child(DpnVpninterfacesList.class),
79 Executors.newListeningSingleThreadExecutor("RouterDpnChangeListener", LOG));
80 this.dataBroker = dataBroker;
81 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
82 this.mdsalManager = mdsalManager;
83 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
84 this.naptSwitchHA = naptSwitchHA;
85 this.idManager = idManager;
86 this.extNetGroupInstaller = extNetGroupInstaller;
87 this.nvpnManager = nvpnManager;
88 this.natServiceManager = natServiceManager;
89 this.coordinator = coordinator;
90 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
91 this.upgradeState = upgradeState;
95 LOG.info("{} init", getClass().getSimpleName());
100 public void close() {
102 Executors.shutdownAndAwaitTermination(getExecutorService());
106 public void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
107 LOG.trace("add : key: {}, value: {}", dpnInfo.key(), dpnInfo);
108 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
109 Uint64 dpnId = dpnInfo.getDpnId();
110 //check router is associated to external network
111 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
112 Optional<Routers> routerData =
113 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
114 LogicalDatastoreType.CONFIGURATION, id);
115 if (routerData.isPresent()) {
116 Routers router = routerData.get();
117 Uuid networkId = router.getNetworkId();
118 if (networkId != null) {
119 if (natMode == NatMode.Conntrack) {
120 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
121 if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
122 LOG.warn("add : NAPT switch is not selected.");
125 //If it is for NAPT switch skip as the flows would be already programmed.
126 if (naptSwitch.equals(dpnId)) {
127 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
130 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
132 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
133 SnatServiceManager.Action.CNT_ROUTER_ENBL);
134 if (router.isEnableSnat()) {
135 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
136 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
138 }), LOG, "Error notifying NAT service manager");
140 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
141 if (routerId == NatConstants.INVALID_ID) {
142 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
145 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
146 routerUuid, networkId);
147 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
148 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
149 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
150 installDefaultNatRouteForRouterExternalSubnets(dpnId,
151 NatUtil.getExternalSubnetIdsFromExternalIps(
152 new ArrayList<ExternalIps>(router.nonnullExternalIps().values())));
153 return Collections.emptyList();
156 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
157 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
158 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
159 return Collections.singletonList(
160 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
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
172 "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
173 dpnId, routerUuid, vpnId);
174 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
176 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
177 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
178 if (vpnId == NatConstants.INVALID_ID) {
179 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
182 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
183 //Install default entry in FIB to SNAT table
184 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
185 + "vpnId {}...", dpnId, routerUuid, vpnId);
186 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
188 /* install V6 internet default fallback rule in FIB_TABLE if router
189 * is having V6 subnet
191 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
192 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.ADD_FLOW);
193 if (router.isEnableSnat()) {
194 LOG.info("add : SNAT enabled for router {}", routerUuid);
195 if (extNwProvType == null) {
196 LOG.error("add : External Network Provider Type missing");
199 NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
200 dpnId, router, routerId, vpnId, confTx, extNwProvType, upgradeState);
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 public 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 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
219 if (routerId == NatConstants.INVALID_ID) {
220 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
223 Uint64 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 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
235 if (naptSwitch == null || naptSwitch.equals(Uint64.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,
246 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
247 SnatServiceManager.Action.CNT_ROUTER_DISBL);
248 if (router.isEnableSnat()) {
249 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
250 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
252 }), LOG, "Error notifying NAT service manager");
254 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
255 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
256 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
257 return Collections.singletonList(
258 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
260 if (vpnName == null) {
261 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
263 if (vpnId == NatConstants.INVALID_ID) {
264 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
267 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
268 //Remove default entry in FIB
269 LOG.debug("remove : Removing default route in FIB on dpn {} ...", dpnId);
270 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, confTx);
272 LOG.debug("remove : External vpn associated to router {}", routerUuid);
273 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
274 if (vpnId == NatConstants.INVALID_ID) {
275 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
278 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
279 //Remove default entry in FIB
280 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
282 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
284 /* remove V6 internet default fallback rule in FIB_TABLE if router
285 * is having V6 subnet
287 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
288 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.DEL_FLOW);
289 if (router.isEnableSnat()) {
290 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
291 routerUuid, networkId);
292 if (extNwProvType == null) {
295 LOG.info("remove : SNAT enabled for router {}", routerUuid);
296 String externalVpnName = NatUtil.getAssociatedVPN(dataBroker,
297 routerData.get().getNetworkId());
298 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, dpnId,
299 router, routerId, vpnId, externalVpnName, extNwProvType, confTx);
301 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
305 }, NatConstants.NAT_DJC_MAX_RETRIES);
306 } // end of controller based SNAT
312 public void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
313 DpnVpninterfacesList update) {
314 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
317 private void installDefaultNatRouteForRouterExternalSubnets(Uint64 dpnId, Collection<Uuid> externalSubnetIds) {
318 if (externalSubnetIds == null) {
319 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
323 for (Uuid subnetId : externalSubnetIds) {
324 Uint32 vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
325 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
326 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
327 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
328 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
330 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);