2ba021bf51c1648cc4fe3434e9e216ce3503f210
[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.genius.infra.Datastore.CONFIGURATION;
11
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;
45
46 @Singleton
47 public class RouterDpnChangeListener
48         extends AsyncDataTreeChangeListenerBase<DpnVpninterfacesList, RouterDpnChangeListener> {
49
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;
63
64     @Inject
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;
88     }
89
90     @Override
91     @PostConstruct
92     public void init() {
93         LOG.info("{} init", getClass().getSimpleName());
94         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
95     }
96
97     @Override
98     protected RouterDpnChangeListener getDataTreeChangeListener() {
99         return RouterDpnChangeListener.this;
100     }
101
102     @Override
103     protected InstanceIdentifier<DpnVpninterfacesList> getWildCardPath() {
104         return InstanceIdentifier.create(NeutronRouterDpns.class).child(RouterDpnList.class)
105             .child(DpnVpninterfacesList.class);
106     }
107
108     @Override
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.");
126                         return;
127                     }
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);
131                         return;
132                     }
133                     ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
134                         confTx -> {
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);
140                             }
141                         }), LOG, "Error notifying NAT service manager");
142                 } else {
143                     Uint32 routerId = NatUtil.getVpnId(dataBroker, routerUuid);
144                     if (routerId == NatConstants.INVALID_ID) {
145                         LOG.error("add : Invalid routerId returned for routerName {}", routerUuid);
146                         return;
147                     }
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();
156                         });
157                     }
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 -> {
163                                 Uint32 vpnId;
164                                 if (vpnName == null) {
165                                     LOG.debug("add : Internal vpn associated to router {}", routerUuid);
166                                     vpnId = routerId;
167                                     if (vpnId == NatConstants.INVALID_ID) {
168                                         LOG.error("add : Invalid vpnId returned for routerName {}", routerUuid);
169                                         return;
170                                     }
171                                     LOG.debug("add : Retrieved vpnId {} for router {}", vpnId, routerUuid);
172                                     //Install default entry in FIB to SNAT table
173                                     LOG.info(
174                                         "add : Installing default route in FIB on dpn {} for router {} with vpn {}",
175                                         dpnId, routerUuid, vpnId);
176                                     snatDefaultRouteProgrammer.installDefNATRouteInDPN(dpnId, vpnId, confTx);
177                                 } else {
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);
182                                         return;
183                                     }
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);
189                                 }
190                                 /* install V6 internet default fallback rule in FIB_TABLE if router
191                                  * is having V6 subnet
192                                  */
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");
199                                         return;
200                                     }
201                                     NatUtil.handleSNATForDPN(dataBroker, mdsalManager, idManager, naptSwitchHA,
202                                         dpnId, router, routerId, vpnId, confTx, extNwProvType, upgradeState);
203                                 } else {
204                                     LOG.info("add : SNAT is not enabled for router {} to handle addDPN event {}",
205                                         routerUuid, dpnId);
206                                 }
207                             }));
208                     }, NatConstants.NAT_DJC_MAX_RETRIES);
209                 } // end of controller based SNAT
210             }
211         } else {
212             LOG.debug("add : Router {} is not associated with External network", routerUuid);
213         }
214     }
215
216     @Override
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);
223             return;
224         }
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.");
239                         return;
240                     }
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);
244                         return;
245                     }
246                     ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
247                         confTx -> {
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);
253                             }
254                         }), LOG, "Error notifying NAT service manager");
255                 } else {
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 -> {
261                                 Uint32 vpnId;
262                                 if (vpnName == null) {
263                                     LOG.debug("remove : Internal vpn associated to router {}", routerUuid);
264                                     vpnId = routerId;
265                                     if (vpnId == NatConstants.INVALID_ID) {
266                                         LOG.error("remove : Invalid vpnId returned for routerName {}", routerUuid);
267                                         return;
268                                     }
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);
273                                 } else {
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);
278                                         return;
279                                     }
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,
283                                         vpnName);
284                                     snatDefaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, vpnId, routerId, confTx);
285                                 }
286                                 /* remove V6 internet default fallback rule in FIB_TABLE if router
287                                  * is having V6 subnet
288                                  */
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) {
295                                         return;
296                                     }
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);
302                                 } else {
303                                     LOG.info("remove : SNAT is not enabled for router {} to handle removeDPN event {}",
304                                         routerUuid, dpnId);
305                                 }
306                             }));
307                     }, NatConstants.NAT_DJC_MAX_RETRIES);
308                 } // end of controller based SNAT
309             }
310         }
311     }
312
313     @Override
314     protected void update(InstanceIdentifier<DpnVpninterfacesList> identifier, DpnVpninterfacesList original,
315                           DpnVpninterfacesList update) {
316         LOG.trace("Update key: {}, original: {}, update: {}", update.key(), original, update);
317     }
318
319     private void installDefaultNatRouteForRouterExternalSubnets(Uint64 dpnId, Collection<Uuid> externalSubnetIds) {
320         if (externalSubnetIds == null) {
321             LOG.error("installDefaultNatRouteForRouterExternalSubnets : No external subnets for router");
322             return;
323         }
324
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());
331             } else {
332                 LOG.debug("installDefaultNatRouteForRouterExternalSubnets : No vpnID for subnet {} found", subnetId);
333             }
334         }
335     }
336 }