9ed83d0511e1bca18d96a152baf307597bfce38e
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / recovery / impl / ItmTepInstanceRecoveryHandler.java
1 /*
2  * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.genius.itm.recovery.impl;
9
10 import java.time.Duration;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Objects;
14 import java.util.concurrent.atomic.AtomicInteger;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
22 import org.opendaylight.genius.interfacemanager.interfaces.IInterfaceManager;
23 import org.opendaylight.genius.itm.cache.DPNTEPsInfoCache;
24 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
25 import org.opendaylight.genius.itm.cache.OfEndPointCache;
26 import org.opendaylight.genius.itm.cache.OvsBridgeEntryCache;
27 import org.opendaylight.genius.itm.cache.OvsBridgeRefEntryCache;
28 import org.opendaylight.genius.itm.cache.TunnelStateCache;
29 import org.opendaylight.genius.itm.confighelpers.ItmExternalTunnelAddWorker;
30 import org.opendaylight.genius.itm.confighelpers.ItmInternalTunnelAddWorker;
31 import org.opendaylight.genius.itm.confighelpers.ItmInternalTunnelDeleteWorker;
32 import org.opendaylight.genius.itm.confighelpers.ItmTepAddWorker;
33 import org.opendaylight.genius.itm.confighelpers.ItmTepRemoveWorker;
34 import org.opendaylight.genius.itm.globals.ITMConstants;
35 import org.opendaylight.genius.itm.impl.ItmUtils;
36 import org.opendaylight.genius.itm.impl.TunnelMonitoringConfig;
37 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
38 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
39 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
40 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
41 import org.opendaylight.serviceutils.srm.ServiceRecoveryInterface;
42 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.TunnelEndPoints;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.dpn.teps.info.tunnel.end.points.TzMembership;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.TransportZone;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.Subnets;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rev160406.transport.zones.transport.zone.subnets.Vteps;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.serviceutils.srm.types.rev180626.GeniusItmTep;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 @Singleton
60 public class ItmTepInstanceRecoveryHandler implements ServiceRecoveryInterface {
61
62     private static final Logger LOG = LoggerFactory.getLogger(ItmTepInstanceRecoveryHandler.class);
63
64     private final JobCoordinator jobCoordinator;
65     private final ItmInternalTunnelAddWorker itmInternalTunnelAddWorker;
66     private final ItmExternalTunnelAddWorker itmExternalTunnelAddWorker;
67     private final DPNTEPsInfoCache dpntePsInfoCache;
68     private final DataBroker dataBroker;
69     private final ItmInternalTunnelDeleteWorker itmInternalTunnelDeleteWorker;
70     private final ItmConfig itmConfig;
71     private final EntityOwnershipUtils entityOwnershipUtils;
72     private final IMdsalApiManager imdsalApiManager;
73     private final DataTreeEventCallbackRegistrar eventCallbacks;
74     private final ManagedNewTransactionRunner txRunner;
75
76     @Inject
77     public ItmTepInstanceRecoveryHandler(DataBroker dataBroker,
78                                          ItmConfig itmConfig,
79                                          IMdsalApiManager imdsalApiMgr,
80                                          JobCoordinator jobCoordinator,
81                                          TunnelMonitoringConfig tunnelMonitoringConfig,
82                                          DPNTEPsInfoCache dpntePsInfoCache, TunnelStateCache tunnelStateCache,
83                                          DirectTunnelUtils directTunnelUtils, DpnTepStateCache dpnTepStateCache,
84                                          OvsBridgeEntryCache ovsBridgeEntryCache,
85                                          OvsBridgeRefEntryCache ovsBridgeRefEntryCache,
86                                          IInterfaceManager interfaceManager,
87                                          ServiceRecoveryRegistry serviceRecoveryRegistry,
88                                          EntityOwnershipUtils entityOwnershipUtils,
89                                          OfEndPointCache ofEndPointCache,
90                                          DataTreeEventCallbackRegistrar eventCallbacks) {
91         this.dataBroker = dataBroker;
92         this.itmConfig = itmConfig;
93         this.imdsalApiManager = imdsalApiMgr;
94         this.jobCoordinator = jobCoordinator;
95         this.dpntePsInfoCache = dpntePsInfoCache;
96         this.entityOwnershipUtils = entityOwnershipUtils;
97         this.eventCallbacks = eventCallbacks;
98         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
99         this.itmInternalTunnelAddWorker = new ItmInternalTunnelAddWorker(dataBroker, jobCoordinator,
100                 tunnelMonitoringConfig, itmConfig, directTunnelUtils, interfaceManager,
101                 ovsBridgeRefEntryCache, ofEndPointCache);
102         this.itmExternalTunnelAddWorker = new ItmExternalTunnelAddWorker(itmConfig,
103                 dpntePsInfoCache);
104         this.itmInternalTunnelDeleteWorker = new ItmInternalTunnelDeleteWorker(dataBroker, jobCoordinator,
105                 tunnelMonitoringConfig, interfaceManager, dpnTepStateCache, ovsBridgeEntryCache,
106                 ovsBridgeRefEntryCache, tunnelStateCache, directTunnelUtils);
107         serviceRecoveryRegistry.registerServiceRecoveryRegistry(getServiceRegistryKey(), this);
108     }
109
110     private String getServiceRegistryKey() {
111         return GeniusItmTep.class.toString();
112     }
113
114     @Override
115     public void recoverService(String entityId) {
116         if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
117             return;
118         }
119         LOG.info("Trigerred recovery of ITM Instance - Tep {}", entityId);
120         try {
121             recoverTep(entityId);
122         } catch (InterruptedException e) {
123             LOG.error("ITM Instance tep has not been recovered.", e);
124         }
125     }
126
127     private void recoverTep(String entityId) throws InterruptedException {
128         List<DPNTEPsInfo> tepsToRecover = new ArrayList<>();
129         String[] params = entityId.split(":");
130         if (params.length < 2) {
131             LOG.error("Not enough arguments..Exiting...");
132         } else if (params.length > 2) {
133             LOG.info("Ignoring extra parameter and proceeding...");
134         }
135         String tzName = params[0];
136         String ipAddress = params[1];
137         TransportZone oldTz = ItmUtils.getTransportZoneFromConfigDS(tzName, dataBroker);
138         DPNTEPsInfo dpnTepsToRecover = extractDPNTepsInfo(tzName, ipAddress, oldTz);
139         if (dpnTepsToRecover == null) {
140             LOG.error("Please Enter appropriate arguments for Tep Recovery.");
141             return;
142         } else {
143             tepsToRecover.add(dpnTepsToRecover);
144             //List of Internel tunnels
145             List<InternalTunnel> tunnelList = ItmUtils.getInternalTunnelsFromCache(dataBroker);
146             List<String> interfaceListToRecover = new ArrayList<>();
147             LOG.debug("List of tunnel interfaces: {}" , tunnelList);
148
149             if (oldTz != null) {
150                 LOG.trace("Deleting transportzone {}", tzName);
151                 ItmTepRemoveWorker tepRemoveWorker = new ItmTepRemoveWorker(tepsToRecover, null, oldTz,
152                     imdsalApiManager, itmInternalTunnelDeleteWorker, dpntePsInfoCache, txRunner);
153                 jobCoordinator.enqueueJob(tzName, tepRemoveWorker);
154                 AtomicInteger eventCallbackCount = new AtomicInteger(0);
155                 AtomicInteger eventRegistrationCount = new AtomicInteger(0);
156                 tunnelList.stream().filter(internalTunnel -> Objects.equals(internalTunnel
157                         .getDestinationDPN(), dpnTepsToRecover.getDPNID()) || Objects.equals(
158                         internalTunnel.getSourceDPN(), dpnTepsToRecover.getDPNID())).forEach(internalTunnel -> {
159                             eventRegistrationCount.incrementAndGet();
160                             interfaceListToRecover.add(String.valueOf(internalTunnel.getTunnelInterfaceNames())); });
161
162                 if (!interfaceListToRecover.isEmpty()) {
163                     interfaceListToRecover.forEach(interfaceName -> {
164                         StateTunnelListKey tlKey = new StateTunnelListKey(interfaceName);
165                         LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, interfaceName);
166                         InstanceIdentifier<StateTunnelList> stListId = ItmUtils.buildStateTunnelListId(tlKey);
167                         eventCallbacks.onRemove(LogicalDatastoreType.OPERATIONAL, stListId, (unused) -> {
168                             LOG.trace("callback event for a delete {} interface instance....", stListId);
169                             // recreating the transportZone
170                             recreateTEP(tzName, tepsToRecover, eventCallbackCount, interfaceListToRecover.size());
171                             return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
172                         }, Duration.ofMillis(5000), (id) -> {
173                                 LOG.trace("event callback timed out for {} tunnel interface ", interfaceName);
174                                 recreateTEP(tzName, tepsToRecover, eventCallbackCount, interfaceListToRecover.size());
175                             });
176                     });
177                 } else {
178                     recreateTEP(tzName, tepsToRecover, eventCallbackCount, interfaceListToRecover.size());
179                 }
180             }
181         }
182     }
183
184
185     private void recreateTEP(String tzName, List tepts, AtomicInteger eventCallbackCount, int registeredEventSize) {
186         eventCallbackCount.incrementAndGet();
187         if (eventCallbackCount.intValue() == registeredEventSize || registeredEventSize == 0) {
188             LOG.info("Re-creating TEP {}", tzName);
189             ItmTepAddWorker tepAddWorker = new ItmTepAddWorker(tepts, null, dataBroker, imdsalApiManager,
190                     itmInternalTunnelAddWorker, itmExternalTunnelAddWorker);
191             jobCoordinator.enqueueJob(tzName, tepAddWorker);
192         } else {
193             LOG.trace("{} call back events registered for {} tunnel interfaces",
194                     registeredEventSize, eventCallbackCount);
195         }
196     }
197
198     private DPNTEPsInfo extractDPNTepsInfo(String tzName, String ipAddress, TransportZone transportZone) {
199
200         if (transportZone == null) {
201             LOG.error("Transportzone name {} is not valid.", tzName);
202             return null;
203         }
204
205         for (Subnets sub : transportZone.nonnullSubnets()) {
206             if (sub.getVteps() == null || sub.getVteps().isEmpty()) {
207                 LOG.error("Transport Zone {} subnet {} has no vteps", transportZone.getZoneName(), sub.getPrefix());
208             }
209             for (Vteps vtep : sub.nonnullVteps()) {
210                 if (ipAddress.equals(vtep.getIpAddress().stringValue())) {
211
212                     List<TzMembership> zones = ItmUtils.createTransportZoneMembership(tzName);
213                     LOG.trace("Transportzone {} found match for tep {} to be recovered", transportZone.getZoneName(),
214                             ipAddress);
215
216                     //OfTunnels is false byDefault
217                     TunnelEndPoints tunnelEndPoints = ItmUtils.createTunnelEndPoints(vtep.getDpnId(),
218                         IpAddressBuilder.getDefaultInstance(ipAddress), vtep.getPortname(), false, sub.getVlanId(),
219                             sub.getPrefix(), sub.getGatewayIp(), zones,transportZone.getTunnelType(),
220                             itmConfig.getDefaultTunnelTos());
221
222                     List<TunnelEndPoints> teps = new ArrayList<>();
223                     teps.add(tunnelEndPoints);
224                     return ItmUtils.createDPNTepInfo(vtep.getDpnId(), teps);
225                 }
226             }
227         }
228         return null;
229     }
230 }