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;
15 import java.math.BigInteger;
16 import java.util.Collections;
17 import java.util.List;
18 import javax.annotation.Nonnull;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
24 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
25 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.infra.Datastore.Configuration;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
31 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
32 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
33 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
34 import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
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.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsalutil.rev170830.Config;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<Config> {
51 private static final Logger LOG = LoggerFactory.getLogger(UpgradeStateListener.class);
53 private final DataBroker dataBroker;
54 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
55 private final NatserviceConfig.NatMode natMode;
56 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
57 private IMdsalApiManager mdsalManager;
58 private IdManagerService idManager;
59 private NaptSwitchHA naptSwitchHA;
60 private final JobCoordinator coordinator;
61 private final ManagedNewTransactionRunner txRunner;
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(Config.class)));
73 this.dataBroker = dataBroker;
74 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
75 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
76 this.defaultRouteProgrammer = defaultRouteProgrammer;
77 this.coordinator = coordinator;
78 this.naptSwitchHA = naptSwitchHA;
80 this.natMode = config.getNatMode();
82 this.natMode = NatserviceConfig.NatMode.Controller;
84 LOG.trace("UpgradeStateListener (nat) initialized");
88 public void add(@Nonnull Config newDataObject) {
92 public void remove(@Nonnull Config removedDataObject) {
93 if (natMode == NatserviceConfig.NatMode.Conntrack) {
96 LOG.debug("Verify is all Elected Napt Switch and connected back post upgrade");
100 public void update(@Nonnull Config original, Config updated) {
101 if (natMode == NatserviceConfig.NatMode.Controller) {
102 if (original.isUpgradeInProgress() && !updated.isUpgradeInProgress()) {
103 Optional<NaptSwitches> npatSwitches = NatUtil.getAllPrimaryNaptSwitches(dataBroker);
104 if (npatSwitches.isPresent()) {
105 for (RouterToNaptSwitch routerToNaptSwitch : npatSwitches.get().getRouterToNaptSwitch()) {
106 BigInteger primaryNaptDpnId = routerToNaptSwitch.getPrimarySwitchId();
107 if (!NatUtil.getSwitchStatus(dataBroker, routerToNaptSwitch.getPrimarySwitchId())) {
108 String routerUuid = routerToNaptSwitch.getRouterName();
109 coordinator.enqueueJob((NatConstants.NAT_DJC_PREFIX + routerUuid),
110 () -> Collections.singletonList(
111 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, confTx -> {
112 reElectNewNaptSwitch(routerUuid, primaryNaptDpnId, confTx);
114 )), NatConstants.NAT_DJC_MAX_RETRIES);
122 LOG.info("UpgradeStateListener update from {} to {}", original, updated);
123 if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
127 SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
130 routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
131 InstanceIdentifier.create(ExtRouters.class));
132 } catch (ReadFailedException e) {
133 LOG.error("Error reading external routers", e);
137 for (Routers router : routers.getRouters()) {
138 List<ExternalIps> externalIps = router.getExternalIps();
139 if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
140 centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
145 private void reElectNewNaptSwitch(String routerName, BigInteger primaryNaptDpnId,
146 TypedReadWriteTransaction<Configuration> confTx) {
147 // Check if this is externalRouter else ignore
148 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
149 Optional<Routers> routerData =
150 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
151 LogicalDatastoreType.CONFIGURATION, extRoutersId);
152 if (!routerData.isPresent()) {
153 LOG.debug("reElectNewNaptSwitch : SNAT->Ignoring Re-election for router {} since its not External Router",
157 Uuid networkId = routerData.get().getNetworkId();
158 if (networkId == null) {
159 LOG.error("hndlTepDelForSnatInEachRtr : SNAT -> Ignoring Re-election with Napt {} for router {}"
160 + "as external network configuraton is missing", primaryNaptDpnId, routerName);
163 long routerId = NatUtil.getVpnId(dataBroker, routerName);
164 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Router {} is associated with ext nw {}", routerId, networkId);
165 Uuid bgpVpnUuid = NatUtil.getVpnForRouter(dataBroker, routerName);
167 if (bgpVpnUuid == null) {
168 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
169 routerId, routerName);
172 bgpVpnId = NatUtil.getVpnId(dataBroker, bgpVpnUuid.getValue());
173 if (bgpVpnId == NatConstants.INVALID_ID) {
174 LOG.error("hndlTepDelForSnatInEachRtr :SNAT->Invalid Private BGP VPN ID returned for routerName {}",
179 defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
180 if (routerData.get().isEnableSnat()) {
181 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
183 long routerVpnId = routerId;
184 if (bgpVpnId != NatConstants.INVALID_ID) {
185 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Private BGP VPN ID (Internal BGP VPN ID) {} "
186 + "associated to the router {}", bgpVpnId, routerName);
187 routerVpnId = bgpVpnId;
189 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
190 + "associated to the router {}", routerVpnId, routerName);
192 //Re-elect the other available switch as the NAPT switch and program the NAT flows.
193 ProviderTypes extNwProvType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker,
194 routerName, networkId);
195 if (extNwProvType == null) {
198 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
199 routerId, routerVpnId, extNwProvType, confTx);
202 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
203 routerId, primaryNaptDpnId);