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.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;
50 public class UpgradeStateListener extends AbstractClusteredSyncDataTreeChangeListener<UpgradeConfig> {
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 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;
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;
82 this.natMode = config.getNatMode();
84 this.natMode = NatserviceConfig.NatMode.Controller;
86 LOG.trace("UpgradeStateListener (nat) initialized");
90 public void add(@NonNull UpgradeConfig newDataObject) {
94 public void remove(@NonNull UpgradeConfig 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 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);
123 LOG.info("UpgradeStateListener update from {} to {}", original, updated);
124 if (!(original.isUpgradeInProgress() && !updated.isUpgradeInProgress())) {
128 SingleTransactionDataBroker reader = new SingleTransactionDataBroker(dataBroker);
131 routers = reader.syncRead(LogicalDatastoreType.CONFIGURATION,
132 InstanceIdentifier.create(ExtRouters.class));
133 } catch (ReadFailedException e) {
134 LOG.error("Error reading external routers", e);
138 for (Routers router : routers.nonnullRouters()) {
139 List<ExternalIps> externalIps = router.getExternalIps();
140 if (router.isEnableSnat() && externalIps != null && !externalIps.isEmpty()) {
141 centralizedSwitchScheduler.scheduleCentralizedSwitch(router);
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",
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);
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);
168 if (bgpVpnUuid == null) {
169 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT->Internal VPN-ID {} associated to router {}",
170 routerId, routerName);
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 {}",
180 defaultRouteProgrammer.removeDefNATRouteInDPN(primaryNaptDpnId, bgpVpnId, confTx);
181 if (routerData.get().isEnableSnat()) {
182 LOG.info("hndlTepDelForSnatInEachRtr : SNAT enabled for router {}", routerId);
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;
190 LOG.debug("hndlTepDelForSnatInEachRtr : SNAT -> Internal L3 VPN ID (Router ID) {} "
191 + "associated to the router {}", routerVpnId, routerName);
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) {
199 NatUtil.removeSNATFromDPN(dataBroker, mdsalManager, idManager, naptSwitchHA, primaryNaptDpnId, routerName,
200 routerId, routerVpnId, networkId, extNwProvType, confTx);
203 LOG.info("hndlTepDelForSnatInEachRtr : SNAT is not enabled for router {} to handle addDPN event {}",
204 routerId, primaryNaptDpnId);