Freeze upstream versions
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / RouterDpnChangeListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
11
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;
48
49 @Singleton
50 public class RouterDpnChangeListener extends AbstractAsyncDataTreeChangeListener<DpnVpninterfacesList> {
51
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;
65
66     @Inject
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;
92     }
93
94     public void init() {
95         LOG.info("{} init", getClass().getSimpleName());
96     }
97
98     @Override
99     @PreDestroy
100     public void close() {
101         super.close();
102         Executors.shutdownAndAwaitTermination(getExecutorService());
103     }
104
105     @Override
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.");
123                         return;
124                     }
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);
128                         return;
129                     }
130                     LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
131                         confTx -> {
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);
137                             }
138                         }), LOG, "Error notifying NAT service manager");
139                 } else {
140                     Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
141                     if (routerId == NatConstants.INVALID_ID) {
142                         LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
143                         return;
144                     }
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();
154                         });
155                     }
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 -> {
161                                 Uint32 vpnId;
162                                 if (vpnName == null) {
163                                     LOG.debug("add : Internal vpn associated to router {}", routerUuid);
164                                     vpnId = routerId;
165                                     if (vpnId == NatConstants.INVALID_ID) {
166                                         LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
167                                         return;
168                                     }
169                                     LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
170                                     //Install default entry in FIB to SNAT table
171                                     LOG.info(
172                                         "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
173                                         dpnId, routerUuid, vpnId);
174                                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
175                                 } else {
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);
180                                         return;
181                                     }
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);
187                                 }
188                                 /* install V6 internet default fallback rule in FIB_TABLE if router
189                                  * is having V6 subnet
190                                  */
191                                 Uuid internetVpnId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
192                                 if (internetVpnId != null) {
193                                     nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid),
194                                             internetVpnId, NwConstants.ADD_FLOW);
195                                 }
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");
200                                         return;
201                                     }
202                                     NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
203                                         dpnId, router, routerId, vpnId, confTx, extNwProvType, upgradeState);
204                                 } else {
205                                     LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
206                                         routerUuid, dpnId);
207                                 }
208                             }));
209                     }, NatConstants.NAT_DJC_MAX_RETRIES);
210                 } // end of controller based SNAT
211             }
212         } else {
213             LOG.debug("add : Router {} is not associated with External network", routerUuid);
214         }
215     }
216
217     @Override
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);
224             return;
225         }
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.");
240                         return;
241                     }
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);
245                         return;
246                     }
247                     LoggingFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
248                         confTx -> {
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);
254                             }
255                         }), LOG, "Error notifying NAT service manager");
256                 } else {
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 -> {
262                                 Uint32 vpnId;
263                                 if (vpnName == null) {
264                                     LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
265                                     vpnId = routerId;
266                                     if (vpnId == NatConstants.INVALID_ID) {
267                                         LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
268                                         return;
269                                     }
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);
274                                 } else {
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);
279                                         return;
280                                     }
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,
284                                         vpnName);
285                                     snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
286                                 }
287                                 /* remove V6 internet default fallback rule in FIB_TABLE if router
288                                  * is having V6 subnet
289                                  */
290                                 Uuid internetVpnId = NatUtil.getVpnIdfromNetworkId(dataBroker, networkId);
291                                 if (internetVpnId != null) {
292                                     nvpnManager.programV6InternetFallbackFlow(new Uuid(routerUuid), internetVpnId,
293                                             NwConstants.DEL_FLOW);
294                                 }
295                                 if (router.isEnableSnat()) {
296                                     ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
297                                         routerUuid, networkId);
298                                     if (extNwProvType == null) {
299                                         return;
300                                     }
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);
306                                 } else {
307                                     LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
308                                         routerUuid, dpnId);
309                                 }
310                             }));
311                     }, NatConstants.NAT_DJC_MAX_RETRIES);
312                 } // end of controller based SNAT
313             }
314         }
315     }
316
317     @Override
318     public void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
319                           DpnVpninterfacesList update) {
320         LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
321     }
322
323     private void installDefaultNatRouteForRouterExternalSubnets(Uint64 dpnId, Collection<Uuid> externalSubnetIds) {
324         if (externalSubnetIds == null) {
325             LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
326             return;
327         }
328
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());
335             } else {
336                 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);
337             }
338         }
339     }
340 }