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.mdsal.binding.util.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.mdsalutil.NwConstants;
21 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
22 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
23 import org.opendaylight.infrautils.utils.concurrent.Executors;
24 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
27 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
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 LoggingFutures.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 Uuid internetVpnId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
192 if (internetVpnId != null) {
193 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
194 internetVpnId, NwConstants.ADD_FLOW);
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 NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
203 dpnId, router, routerId, vpnId, confTx, extNwProvType, upgradeState);
205 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
209 }, NatConstants.NAT_DJC_MAX_RETRIES);
210 } // end of controller based SNAT
213 LOG.debug("add : Router {} is not associated with External network", routerUuid);
218 public void remove(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList dpnInfo) {
219 LOG.trace("remove : key: {}, value: {}", dpnInfo.key(), dpnInfo);
220 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
221 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
222 if (routerId == NatConstants.INVALID_ID) {
223 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
226 Uint64 dpnId = dpnInfo.getDpnId();
227 //check router is associated to external network
228 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
229 Optional<Routers> routerData =
230 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
231 LogicalDatastoreType.CONFIGURATION, id);
232 if (routerData.isPresent()) {
233 Routers router = routerData.get();
234 Uuid networkId = router.getNetworkId();
235 if (networkId != null) {
236 if (natMode == NatMode.Conntrack) {
237 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
238 if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
239 LOG.warn("remove : NAPT switch is not selected.");
242 //If it is for NAPT switch skip as the flows would be already programmed.
243 if (naptSwitch.equals(dpnId)) {
244 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
247 LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
249 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
250 SnatServiceManager.Action.CNT_ROUTER_DISBL);
251 if (router.isEnableSnat()) {
252 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
253 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
255 }), LOG, "Error notifying NAT service manager");
257 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
258 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
259 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
260 return Collections.singletonList(
261 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
263 if (vpnName == null) {
264 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
266 if (vpnId == NatConstants.INVALID_ID) {
267 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
270 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
271 //Remove default entry in FIB
272 LOG.debug("remove : Removing default route in FIB on dpn {} ...", dpnId);
273 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, confTx);
275 LOG.debug("remove : External vpn associated to router {}", routerUuid);
276 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
277 if (vpnId == NatConstants.INVALID_ID) {
278 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
281 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
282 //Remove default entry in FIB
283 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
285 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
287 /* remove V6 internet default fallback rule in FIB_TABLE if router
288 * is having V6 subnet
290 Uuid internetVpnId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
291 if (internetVpnId != null) {
292 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid), internetVpnId,
293 NwConstants.DEL_FLOW);
295 if (router.isEnableSnat()) {
296 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
297 routerUuid, networkId);
298 if (extNwProvType == null) {
301 LOG.info("remove : SNAT enabled for router {}", routerUuid);
302 String externalVpnName = NatUtil.getAssociatedVPN(dataBroker,
303 routerData.get().getNetworkId());
304 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, dpnId,
305 router, routerId, vpnId, externalVpnName, extNwProvType, confTx);
307 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
311 }, NatConstants.NAT_DJC_MAX_RETRIES);
312 } // end of controller based SNAT
318 public void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
319 DpnVpninterfacesList update) {
320 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
323 private void installDefaultNatRouteForRouterExternalSubnets(Uint64 dpnId, Collection<Uuid> externalSubnetIds) {
324 if (externalSubnetIds == null) {
325 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
329 for (Uuid subnetId : externalSubnetIds) {
330 Uint32 vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
331 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
332 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
333 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
334 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
336 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);