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.util.Collection;
14 import java.util.Collections;
15 import javax.annotation.PostConstruct;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
21 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
24 import org.opendaylight.genius.mdsalutil.NwConstants;
25 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
28 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
29 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
30 import org.opendaylight.serviceutils.upgrade.UpgradeState;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.NeutronRouterDpns;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.RouterDpnList;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.neutron.router.dpns.router.dpn.list.DpnVpninterfacesList;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig.NatMode;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.opendaylight.yangtools.yang.common.Uint32;
42 import org.opendaylight.yangtools.yang.common.Uint64;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
47 public class RouterDpnChangeListener
48 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
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(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
76 this.dataBroker = dataBroker;
77 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
78 this.mdsalManager = mdsalManager;
79 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
80 this.naptSwitchHA = naptSwitchHA;
81 this.idManager = idManager;
82 this.extNetGroupInstaller = extNetGroupInstaller;
83 this.nvpnManager = nvpnManager;
84 this.natServiceManager = natServiceManager;
85 this.coordinator = coordinator;
86 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
87 this.upgradeState = upgradeState;
93 LOG.info("{} init", getClass().getSimpleName());
94 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
98 protected RouterDpnChangeListener getDataTreeChangeListener() {
99 return RouterDpnChangeListener.this;
103 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
104 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
105 .child(DpnVpninterfacesList.class);
109 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
110 LOG.trace("add : key: {}, value: {}", dpnInfo.key(), dpnInfo);
111 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
112 Uint64 dpnId = dpnInfo.getDpnId();
113 //check router is associated to external network
114 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
115 Optional<Routers> routerData =
116 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
117 LogicalDatastoreType.CONFIGURATION, id);
118 if (routerData.isPresent()) {
119 Routers router = routerData.get();
120 Uuid networkId = router.getNetworkId();
121 if (networkId != null) {
122 if (natMode == NatMode.Conntrack) {
123 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
124 if (naptSwitch == null || naptSwitch.equals(Uint64.ZERO)) {
125 LOG.warn("add : NAPT switch is not selected.");
128 //If it is for NAPT switch skip as the flows would be already programmed.
129 if (naptSwitch.equals(dpnId)) {
130 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
133 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
135 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
136 SnatServiceManager.Action.CNT_ROUTER_ENBL);
137 if (router.isEnableSnat()) {
138 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
139 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
141 }), LOG, "Error notifying NAT service manager");
143 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
144 if (routerId == NatConstants.INVALID_ID) {
145 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
148 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
149 routerUuid, networkId);
150 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
151 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
152 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
153 installDefaultNatRouteForRouterExternalSubnets(dpnId,
154 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
155 return Collections.emptyList();
158 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
159 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
160 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
161 return Collections.singletonList(
162 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
164 if (vpnName == null) {
165 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
167 if (vpnId == NatConstants.INVALID_ID) {
168 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
171 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
172 //Install default entry in FIB to SNAT table
174 "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
175 dpnId, routerUuid, vpnId);
176 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
178 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
179 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
180 if (vpnId == NatConstants.INVALID_ID) {
181 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
184 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
185 //Install default entry in FIB to SNAT table
186 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
187 + "vpnId {}...", dpnId, routerUuid, vpnId);
188 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
190 /* install V6 internet default fallback rule in FIB_TABLE if router
191 * is having V6 subnet
193 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
194 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.ADD_FLOW);
195 if (router.isEnableSnat()) {
196 LOG.info("add : SNAT enabled for router {}", routerUuid);
197 if (extNwProvType == null) {
198 LOG.error("add : External Network Provider Type missing");
201 NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
202 dpnId, router, routerId, vpnId, confTx, extNwProvType, upgradeState);
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 Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
221 if (routerId == NatConstants.INVALID_ID) {
222 LOG.error("REMOVE: Invalid routId returned for routerName {}",routerUuid);
225 Uint64 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 Uint64 naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
237 if (naptSwitch == null || naptSwitch.equals(Uint64.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,
248 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
249 SnatServiceManager.Action.CNT_ROUTER_DISBL);
250 if (router.isEnableSnat()) {
251 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
252 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
254 }), LOG, "Error notifying NAT service manager");
256 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
257 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
258 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
259 return Collections.singletonList(
260 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
262 if (vpnName == null) {
263 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
265 if (vpnId == NatConstants.INVALID_ID) {
266 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
269 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
270 //Remove default entry in FIB
271 LOG.debug("remove : Removing default route in FIB on dpn {} ...", dpnId);
272 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, confTx);
274 LOG.debug("remove : External vpn associated to router {}", routerUuid);
275 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
276 if (vpnId == NatConstants.INVALID_ID) {
277 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
280 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
281 //Remove default entry in FIB
282 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
284 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
286 /* remove V6 internet default fallback rule in FIB_TABLE if router
287 * is having V6 subnet
289 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
290 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.DEL_FLOW);
291 if (router.isEnableSnat()) {
292 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
293 routerUuid, networkId);
294 if (extNwProvType == null) {
297 LOG.info("remove : SNAT enabled for router {}", routerUuid);
298 String externalVpnName = NatUtil.getAssociatedVPN(dataBroker,
299 routerData.get().getNetworkId());
300 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, dpnId,
301 router, routerId, vpnId, externalVpnName, extNwProvType, confTx);
303 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
307 }, NatConstants.NAT_DJC_MAX_RETRIES);
308 } // end of controller based SNAT
314 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
315 DpnVpninterfacesList update) {
316 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
319 private void installDefaultNatRouteForRouterExternalSubnets(Uint64 dpnId, Collection<Uuid> externalSubnetIds) {
320 if (externalSubnetIds == null) {
321 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
325 for (Uuid subnetId : externalSubnetIds) {
326 Uint32 vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
327 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
328 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
329 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
330 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
332 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);