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 java.util.concurrent.ExecutionException;
20 import javax.annotation.Nonnull;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.infra.Datastore.Configuration;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
31 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
33 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.netvirt.natservice.api.CentralizedSwitchScheduler;
36 import org.opendaylight.serviceutils.tools.mdsal.listener.AbstractClusteredSyncDataTreeChangeListener;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.config.rev170206.NatserviceConfig;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExtRouters;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.NaptSwitches;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.routers.ExternalIps;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.napt.switches.RouterToNaptSwitch;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsalutil.rev170830.Config;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<Config> {
53 private static final Logger LOG = LoggerFactory.getLogger(UpgradeStateListener.class);
55 private final DataBroker dataBroker;
56 private final CentralizedSwitchScheduler centralizedSwitchScheduler;
57 private final NatserviceConfig.NatMode natMode;
58 private SNATDefaultRouteProgrammer defaultRouteProgrammer;
59 private IMdsalApiManager mdsalManager;
60 private IdManagerService idManager;
61 private NaptSwitchHA naptSwitchHA;
62 private final JobCoordinator coordinator;
63 private final ManagedNewTransactionRunner txRunner;
66 public UpgradeStateListener(final DataBroker dataBroker,
67 final CentralizedSwitchScheduler centralizedSwitchScheduler,
68 final SNATDefaultRouteProgrammer defaultRouteProgrammer,
69 final IMdsalApiManager mdsalManager,
70 final IdManagerService idManager,
71 final NaptSwitchHA naptSwitchHA,
72 final NatserviceConfig config, final JobCoordinator coordinator) {
73 super(dataBroker, new DataTreeIdentifier<>(
74 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Config.class)));
75 this.dataBroker = dataBroker;
76 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
77 this.centralizedSwitchScheduler = centralizedSwitchScheduler;
78 this.defaultRouteProgrammer = defaultRouteProgrammer;
79 this.coordinator = coordinator;
80 this.naptSwitchHA = naptSwitchHA;
82 this.natMode = config.getNatMode();
84 this.natMode = NatserviceConfig.NatMode.Controller;
86 LOG.trace("UpgradeStateListener (nat) initialized");
90 public void add(@Nonnull Config newDataObject) {
94 public void remove(@Nonnull Config removedDataObject) {
95 if (natMode == NatserviceConfig.NatMode.Conntrack) {
98 LOG.debug("Verify is all Elected Napt Switch and connected back post upgrade");
102 public void update(@Nonnull Config original, Config 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().getRouterToNaptSwitch()) {
108 BigInteger 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, confTx -> {
114 reElectNewNaptSwitch(routerUuid, primaryNaptDpnId, confTx);
116 )), NatConstants.NAT_DJC_MAX_RETRIES);
124 LOG.info("UpgradeStateListener update from {} to {}", original, updated);
125 if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
129 SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
132 routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
133 InstanceIdentifier.create(ExtRouters.class));
134 } catch (ReadFailedException e) {
135 LOG.error("Error reading external routers", e);
139 for (Routers router : routers.getRouters()) {
140 List<ExternalIps> externalIps = router.getExternalIps();
141 if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
142 centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
147 private void reElectNewNaptSwitch(String routerName, BigInteger primaryNaptDpnId,
148 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
149 // Check if this is externalRouter else ignore
150 InstanceIdentifier<Routers> extRoutersId = NatUtil.buildRouterIdentifier(routerName);
151 Optional<Routers> routerData =
152 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
153 LogicalDatastoreType.CONFIGURATION, extRoutersId);
154 if (!routerData.isPresent()) {
155 LOG.debug("reElectNewNaptSwitch : SNAT->Ignoring Re-election for router {} since its not External Router",
159 Uuid networkId = routerData.get().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);
165 long 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);
169 if (bgpVpnUuid == null) {
170 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
171 routerId, routerName);
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 {}",
181 defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
182 if (routerData.get().isEnableSnat()) {
183 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
185 long 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;
191 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
192 + "associated to the router {}", routerVpnId, routerName);
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 if (extNwProvType == null) {
200 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
201 routerId, routerVpnId, extNwProvType, confTx);
204 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
205 routerId, primaryNaptDpnId);