Bump odlparent->6.0.0,mdsal->5.0.3
[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         Uuid networkId = routerData.get().getNetworkId();
159         if (networkId == null) {
160             LOG.error("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring Re-election  with Napt {} for router {}"
161                     + "as external network configuraton is missing", primaryNaptDpnId, routerName);
162             return;
163         }
164         Uint32 routerId = NatUtil.getVpnId(dataBroker, routerName);
165         LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
166         Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
167         Uint32 bgpVpnId;
168         if (bgpVpnUuid == null) {
169             LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
170                     routerId, routerName);
171             bgpVpnId = routerId;
172         } else {
173             bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
174             if (bgpVpnId == NatConstants.INVALID_ID) {
175                 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
176                         routerName);
177                 return;
178             }
179         }
180         defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
181         if (routerData.get().isEnableSnat()) {
182             LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
183
184             Uint32 routerVpnId = routerId;
185             if (bgpVpnId != NatConstants.INVALID_ID) {
186                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
187                         + "associated to the router {}", bgpVpnId, routerName);
188                 routerVpnId = bgpVpnId;
189             } else {
190                 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
191                         + "associated to the router {}", routerVpnId, routerName);
192             }
193             //Re-elect the other available switch as the NAPT switch and program the NAT flows.
194             ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
195                     routerName, networkId);
196             if (extNwProvType == null) {
197                 return;
198             }
199             NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
200                     routerId, routerVpnId, networkId, extNwProvType, confTx);
201
202         } else {
203             LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
204                     routerId, primaryNaptDpnId);
205         }
206     }
207
208 }