2 * Copyright (c) 2017 Red Hat, Inc. 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
9 package org.opendaylight.netvirt.natservice.internal;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import com.google.common.base.Optional;
14 import java.math.BigInteger;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.concurrent.ExecutionException;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.infra.Datastore.Configuration;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
30 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
31 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
32 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
33 import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
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.rev160111.ExtRouters;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
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.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.upgrade.rev180702.UpgradeConfig;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
49 public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<UpgradeConfig> {
50 private static final Logger LOG = LoggerFactory.getLogger(UpgradeStateListener.class);
52 private final DataBroker dataBroker;
53 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
54 private final NatserviceConfig.NatMode natMode;
55 private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
56 private IMdsalApiManager mdsalManager;
57 private IdManagerService idManager;
58 private final NaptSwitchHA naptSwitchHA;
59 private final JobCoordinator coordinator;
60 private final ManagedNewTransactionRunner txRunner;
63 public UpgradeStateListener(final DataBroker dataBroker,
64 final CentralizedSwitchScheduler centralizedSwitchScheduler,
65 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
66 final IMdsalApiManager mdsalManager,
67 final IdManagerService idManager,
68 final NaptSwitchHA naptSwitchHA,
69 final NatserviceConfig config, final JobCoordinator coordinator) {
70 super(dataBroker, new DataTreeIdentifier<>(
71 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(UpgradeConfig.class)));
72 this.dataBroker = dataBroker;
73 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
74 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
75 this.defaultRouteProgrammer = defaultRouteProgrammer;
76 this.coordinator = coordinator;
77 this.naptSwitchHA = naptSwitchHA;
79 this.natMode = config.getNatMode();
81 this.natMode = NatserviceConfig.NatMode.Controller;
83 LOG.trace("UpgradeStateListener (nat) initialized");
87 public void add(@NonNull UpgradeConfig newDataObject) {
91 public void remove(@NonNull UpgradeConfig removedDataObject) {
92 if (natMode == NatserviceConfig.NatMode.Conntrack) {
95 LOG.debug("Verify is all Elected Napt Switch and connected back post upgrade");
99 public void update(@NonNull UpgradeConfig original, UpgradeConfig updated) {
100 if (natMode == NatserviceConfig.NatMode.Controller) {
101 if (original.isUpgradeInProgress() && !updated.isUpgradeInProgress()) {
102 Optional<NaptSwitches> npatSwitches = NatUtil.getAllPrimaryNaptSwitches(dataBroker);
103 if (npatSwitches.isPresent()) {
104 for (RouterToNaptSwitch routerToNaptSwitch : npatSwitches.get().nonnullRouterToNaptSwitch()) {
105 BigInteger primaryNaptDpnId = routerToNaptSwitch.getPrimarySwitchId();
106 if (!NatUtil.getSwitchStatus(dataBroker, routerToNaptSwitch.getPrimarySwitchId())) {
107 String routerUuid = routerToNaptSwitch.getRouterName();
108 coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + routerUuid,
109 () -> Collections.singletonList(
110 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
111 confTx -> reElectNewNaptSwitch(routerUuid, primaryNaptDpnId, confTx)
112 )), NatConstants.NAT_DJC_MAX_RETRIES);
120 LOG.info("UpgradeStateListener update from {} to {}", original, updated);
121 if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
125 SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
128 routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
129 InstanceIdentifier.create(ExtRouters.class));
130 } catch (ReadFailedException e) {
131 LOG.error("Error reading external routers", e);
135 for (Routers router : routers.nonnullRouters()) {
136 List<ExternalIps> externalIps = router.getExternalIps();
137 if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
138 centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
143 private void reElectNewNaptSwitch(String routerName, BigInteger primaryNaptDpnId,
144 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
145 // Check if this is externalRouter else ignore
146 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
147 Optional<Routers> routerData =
148 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
149 LogicalDatastoreType.CONFIGURATION, extRoutersId);
150 if (!routerData.isPresent()) {
151 LOG.debug("reElectNewNaptSwitch : SNAT->Ignoring Re-election for router {} since its not External Router",
155 Uuid networkId = routerData.get().getNetworkId();
156 if (networkId == null) {
157 LOG.error("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring Re-election with Napt {} for router {}"
158 + "as external network configuraton is missing", primaryNaptDpnId, routerName);
161 long routerId = NatUtil.getVpnId(dataBroker, routerName);
162 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
163 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
165 if (bgpVpnUuid == null) {
166 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
167 routerId, routerName);
170 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
171 if (bgpVpnId == NatConstants.INVALID_ID) {
172 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
177 defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
178 if (routerData.get().isEnableSnat()) {
179 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
181 long routerVpnId = routerId;
182 if (bgpVpnId != NatConstants.INVALID_ID) {
183 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
184 + "associated to the router {}", bgpVpnId, routerName);
185 routerVpnId = bgpVpnId;
187 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
188 + "associated to the router {}", routerVpnId, routerName);
190 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
191 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
192 routerName, networkId);
193 if (extNwProvType == null) {
196 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
197 routerId, routerVpnId, extNwProvType, confTx);
200 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
201 routerId, primaryNaptDpnId);