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.math.BigInteger;
14 import java.util.Collection;
15 import java.util.Collections;
16 import javax.annotation.PostConstruct;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
25 import org.opendaylight.genius.mdsalutil.NwConstants;
26 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
27 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
28 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
29 import org.opendaylight.netvirt.natservice.api.SnatServiceManager;
30 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
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.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 public class RouterDpnChangeListener
47 extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
49 private static final Logger LOG = LoggerFactory.getLogger(RouterDpnChangeListener.class);
50 private final DataBroker dataBroker;
51 private final ManagedNewTransactionRunner txRunner;
52 private final IMdsalApiManager mdsalManager;
53 private final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer;
54 private final NaptSwitchHA naptSwitchHA;
55 private final IdManagerService idManager;
56 private final INeutronVpnManager nvpnManager;
57 private final ExternalNetworkGroupInstaller extNetGroupInstaller;
58 private final JobCoordinator coordinator;
59 private final SnatServiceManager natServiceManager;
60 private final NatMode natMode;
61 private final UpgradeState upgradeState;
64 public RouterDpnChangeListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
65 final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
66 final NaptSwitchHA naptSwitchHA,
67 final IdManagerService idManager,
68 final ExternalNetworkGroupInstaller extNetGroupInstaller,
69 final INeutronVpnManager nvpnManager,
70 final SnatServiceManager natServiceManager,
71 final NatserviceConfig config,
72 final JobCoordinator coordinator,
73 final UpgradeState upgradeState) {
74 super(DpnVpninterfacesList.class, RouterDpnChangeListener.class);
75 this.dataBroker = dataBroker;
76 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
77 this.mdsalManager = mdsalManager;
78 this.snatDefaultRouteProgrammer = snatDefaultRouteProgrammer;
79 this.naptSwitchHA = naptSwitchHA;
80 this.idManager = idManager;
81 this.extNetGroupInstaller = extNetGroupInstaller;
82 this.nvpnManager = nvpnManager;
83 this.natServiceManager = natServiceManager;
84 this.coordinator = coordinator;
85 this.natMode = config != null ? config.getNatMode() : NatMode.Controller;
86 this.upgradeState = upgradeState;
92 LOG.info("{} init", getClass().getSimpleName());
93 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
97 protected RouterDpnChangeListener getDataTreeChangeListener() {
98 return RouterDpnChangeListener.this;
102 protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
103 return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
104 .child(DpnVpninterfacesList.class);
108 protected void add(final InstanceIdentifier<DpnVpninterfacesList> identifier, final DpnVpninterfacesList dpnInfo) {
109 LOG.trace("add : key: {}, value: {}", dpnInfo.key(), dpnInfo);
110 final String routerUuid = identifier.firstKeyOf(RouterDpnList.class).getRouterId();
111 BigInteger dpnId = dpnInfo.getDpnId();
112 //check router is associated to external network
113 InstanceIdentifier<Routers> id = NatUtil.buildRouterIdentifier(routerUuid);
114 Optional<Routers> routerData =
115 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
116 LogicalDatastoreType.CONFIGURATION, id);
117 if (routerData.isPresent()) {
118 Routers router = routerData.get();
119 Uuid networkId = router.getNetworkId();
120 if (networkId != null) {
121 if (natMode == NatMode.Conntrack) {
122 BigInteger naptSwitch = NatUtil.getPrimaryNaptfromRouterName(dataBroker, router.getRouterName());
123 if (naptSwitch == null || naptSwitch.equals(BigInteger.ZERO)) {
124 LOG.warn("add : NAPT switch is not selected.");
127 //If it is for NAPT switch skip as the flows would be already programmed.
128 if (naptSwitch.equals(dpnId)) {
129 LOG.debug("Skipping the notification recived for NAPT switch {}", routerUuid);
132 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
134 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
135 SnatServiceManager.Action.CNT_ROUTER_ENBL);
136 if (router.isEnableSnat()) {
137 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
138 SnatServiceManager.Action.SNAT_ROUTER_ENBL);
140 }), LOG, "Error notifying NAT service manager");
142 Long routerId = NatUtil.getVpnId(dataBroker, routerUuid);
143 if (routerId == NatConstants.INVALID_ID) {
144 LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
147 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
148 routerUuid, networkId);
149 if (extNwProvType == ProviderTypes.FLAT || extNwProvType == ProviderTypes.VLAN) {
150 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + networkId, () -> {
151 extNetGroupInstaller.installExtNetGroupEntries(networkId, dpnId);
152 installDefaultNatRouteForRouterExternalSubnets(dpnId,
153 NatUtil.getExternalSubnetIdsFromExternalIps(router.getExternalIps()));
154 return Collections.emptyList();
157 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + router.getRouterName(), () -> {
158 LOG.debug("add : Router {} is associated with ext nw {}", routerUuid, networkId);
159 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
160 return Collections.singletonList(
161 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
163 if (vpnName == null) {
164 LOG.debug("add : Internal vpn associated to router {}", routerUuid);
166 if (vpnId == NatConstants.INVALID_ID) {
167 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
170 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
171 //Install default entry in FIB to SNAT table
173 "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
174 dpnId, routerUuid, vpnId);
175 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
177 LOG.debug("add : External BGP vpn associated to router {}", routerUuid);
178 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
179 if (vpnId == NatConstants.INVALID_ID) {
180 LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
183 LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
184 //Install default entry in FIB to SNAT table
185 LOG.debug("add : Installing default route in FIB on dpn {} for routerId {} with "
186 + "vpnId {}...", dpnId, routerUuid, vpnId);
187 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
189 /* install V6 internet default fallback rule in FIB_TABLE if router
190 * is having V6 subnet
192 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
193 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.ADD_FLOW);
194 if (router.isEnableSnat()) {
195 LOG.info("add : SNAT enabled for router {}", routerUuid);
196 if (extNwProvType == null) {
197 LOG.error("add : External Network Provider Type missing");
200 NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, dpnId,
201 router, routerId, vpnId, confTx, extNwProvType, upgradeState);
203 LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
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.key(), 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 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
247 natServiceManager.notify(confTx, router, null, naptSwitch, dpnId,
248 SnatServiceManager.Action.CNT_ROUTER_DISBL);
249 if (router.isEnableSnat()) {
250 natServiceManager.notify(confTx, router, null, naptSwitch, naptSwitch,
251 SnatServiceManager.Action.SNAT_ROUTER_DISBL);
253 }), LOG, "Error notifying NAT service manager");
255 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid, () -> {
256 LOG.debug("remove : Router {} is associated with ext nw {}", routerUuid, networkId);
257 Uuid vpnName = NatUtil.getVpnForRouter(dataBroker, routerUuid);
258 return Collections.singletonList(
259 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
261 if (vpnName == null) {
262 LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
264 if (vpnId == NatConstants.INVALID_ID) {
265 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
268 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
269 //Remove default entry in FIB
270 LOG.debug("remove : Removing default route in FIB on dpn {} ...", dpnId);
271 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, confTx);
273 LOG.debug("remove : External vpn associated to router {}", routerUuid);
274 vpnId = NatUtil.getVpnId(dataBroker, vpnName.getValue());
275 if (vpnId == NatConstants.INVALID_ID) {
276 LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
279 LOG.debug("remove : Retrieved vpnId {} for router {}", vpnId, routerUuid);
280 //Remove default entry in FIB
281 LOG.debug("remove : Removing default route in FIB on dpn {} for vpn {} ...", dpnId,
283 snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
285 /* remove V6 internet default fallback rule in FIB_TABLE if router
286 * is having V6 subnet
288 nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
289 NatUtil.getVpnIdfromNetworkId(dataBroker, networkId), NwConstants.DEL_FLOW);
290 if (router.isEnableSnat()) {
291 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
292 routerUuid, networkId);
293 if (extNwProvType == null) {
296 LOG.info("remove : SNAT enabled for router {}", routerUuid);
297 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
298 dpnId, routerUuid, routerId, vpnId, networkId, extNwProvType, confTx);
300 LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
304 }, NatConstants.NAT_DJC_MAX_RETRIES);
305 } // end of controller based SNAT
311 protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
312 DpnVpninterfacesList update) {
313 LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
316 private void installDefaultNatRouteForRouterExternalSubnets(BigInteger dpnId, Collection<Uuid> externalSubnetIds) {
317 if (externalSubnetIds == null) {
318 LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
322 for (Uuid subnetId : externalSubnetIds) {
323 long vpnIdForSubnet = NatUtil.getExternalSubnetVpnId(dataBroker, subnetId);
324 if (vpnIdForSubnet != NatConstants.INVALID_ID) {
325 LOG.info("installDefaultNatRouteForRouterExternalSubnets : Installing default routes in FIB on dpn {} "
326 + "for subnetId {} with vpnId {}", dpnId, subnetId, vpnIdForSubnet);
327 snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnIdForSubnet, subnetId.getValue());
329 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);