DS READ Optimization in NAT
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / UpgradeStateListener.java
1 /*
2  * Copyright (c) 2017 Red Hat, Inc. 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12
13 import com.google.common.base.Optional;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.concurrent.ExecutionException;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.eclipse.jdt.annotation.NonNull;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
25 import org.opendaylight.genius.infra.Datastore.Configuration;
26 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
28 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
29 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
30 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
31 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
32 import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
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.natservice.config.rev170206.NatserviceConfig;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
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.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.upgrade.rev180702.UpgradeConfig;
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 UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<UpgradeConfig> {
51     private static final Logger LOG = LoggerFactory.getLogger(UpgradeStateListener.class);
52
53     private final DataBroker dataBroker;
54     private final CentralizedSwitchScheduler centralizedSwitchScheduler;
55     private final NatserviceConfig.NatMode natMode;
56     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
57     private IMdsalApiManager mdsalManager;
58     private IdManagerService idManager;
59     private final NaptSwitchHA naptSwitchHA;
60     private final JobCoordinator coordinator;
61     private final ManagedNewTransactionRunner txRunner;
62
63     @Inject
64     public UpgradeStateListener(final DataBroker dataBroker,
65                                 final CentralizedSwitchScheduler centralizedSwitchScheduler,
66                                 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
67                                 final IMdsalApiManager mdsalManager,
68                                 final IdManagerService idManager,
69                                 final NaptSwitchHA naptSwitchHA,
70                                 final NatserviceConfig config, final JobCoordinator coordinator) {
71         super(dataBroker, new DataTreeIdentifier<>(
72                 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(UpgradeConfig.class)));
73         this.dataBroker = dataBroker;
74         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
75         this.centralizedSwitchScheduler = centralizedSwitchScheduler;
76         this.defaultRouteProgrammer = defaultRouteProgrammer;
77         this.mdsalManager = mdsalManager;
78         this.idManager = idManager;
79         this.coordinator = coordinator;
80         this.naptSwitchHA = naptSwitchHA;
81         if (config != null) {
82             this.natMode = config.getNatMode();
83         } else {
84             this.natMode = NatserviceConfig.NatMode.Controller;
85         }
86         LOG.trace("UpgradeStateListener (nat) initialized");
87     }
88
89     @Override
90     public void add(@NonNull UpgradeConfig newDataObject) {
91     }
92
93     @Override
94     public void remove(@NonNull UpgradeConfig removedDataObject) {
95         if (natMode == NatserviceConfig.NatMode.Conntrack) {
96             return;
97         }
98         LOG.debug("Verify is all Elected Napt Switch and connected back post upgrade");
99     }
100
101     @Override
102     public void update(@NonNull UpgradeConfig original, UpgradeConfig updated) {
103         if (natMode == NatserviceConfig.NatMode.Controller) {
104             if (original.isUpgradeInProgress() && !updated.isUpgradeInProgress()) {
105                 Optional<NaptSwitches> npatSwitches = NatUtil.getAllPrimaryNaptSwitches(dataBroker);
106                 if (npatSwitches.isPresent()) {
107                     for (RouterToNaptSwitch routerToNaptSwitch : npatSwitches.get().nonnullRouterToNaptSwitch()) {
108                         Uint64 primaryNaptDpnId = routerToNaptSwitch.getPrimarySwitchId();
109                         if (!NatUtil.getSwitchStatus(dataBroker, routerToNaptSwitch.getPrimarySwitchId())) {
110                             String routerUuid = routerToNaptSwitch.getRouterName();
111                             coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid,
112                                 () -> Collections.singletonList(
113                                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
114                                         confTx -> reElectNewNaptSwitch(routerUuid, primaryNaptDpnId, confTx)
115                                 )), NatConstants.NAT_DJC_MAX_RETRIES);
116                         }
117                     }
118                 }
119             }
120             return;
121         }
122
123         LOG.info("UpgradeStateListener update from {} to {}", original, updated);
124         if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
125             return;
126         }
127
128         SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
129         ExtRouters routers;
130         try {
131             routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
132                     InstanceIdentifier.create(ExtRouters.class));
133         } catch (ReadFailedException e) {
134             LOG.error("Error reading external routers", e);
135             return;
136         }
137
138         for (Routers router : routers.nonnullRouters()) {
139             List<ExternalIps> externalIps = router.getExternalIps();
140             if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
141                 centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
142             }
143         }
144     }
145
146     private void reElectNewNaptSwitch(String routerName, Uint64 primaryNaptDpnId,
147             TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
148         // Check if this is externalRouter else ignore
149         InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
150         Optional<Routers> routerData =
151                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
152                         LogicalDatastoreType.CONFIGURATION, extRoutersId);
153         if (!routerData.isPresent()) {
154             LOG.debug("reElectNewNaptSwitch : SNAT->Ignoring Re-election for router {} since its not External Router",
155                     routerName);
156             return;
157         }
158         Routers extRouters = routerData.get();
159         Uuid networkId = extRouters.getNetworkId();
160         if (networkId == null) {
161             LOG.error("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring Re-election  with Napt {} for router {}"
162                     + "as external network configuraton is missing", primaryNaptDpnId, routerName);
163             return;
164         }
165         Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
166         LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
167         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
168         Uint32 bgpVpnId;
169         if (bgpVpnUuid == null) {
170             LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
171                     routerId, routerName);
172             bgpVpnId = routerId;
173         } else {
174             bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
175             if (bgpVpnId == NatConstants.INVALID_ID) {
176                 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
177                         routerName);
178                 return;
179             }
180         }
181         defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
182         if (routerData.get().isEnableSnat()) {
183             LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
184
185             Uint32 routerVpnId = routerId;
186             if (bgpVpnId != NatConstants.INVALID_ID) {
187                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
188                         + "associated to the router {}", bgpVpnId, routerName);
189                 routerVpnId = bgpVpnId;
190             } else {
191                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
192                         + "associated to the router {}", routerVpnId, routerName);
193             }
194             //Re-elect the other available switch as the NAPT switch and program the NAT flows.
195             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
196                     routerName, networkId);
197             String externalVpnName = NatUtil.getAssociatedVPN(dataBroker,extRouters.getNetworkId());
198             if (extNwProvType == null) {
199                 return;
200             }
201             NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, extRouters,
202                     routerId, routerVpnId, externalVpnName, extNwProvType, confTx);
203
204         } else {
205             LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
206                     routerId, primaryNaptDpnId);
207         }
208     }
209
210 }