Fix: Tunnels are in UNKNOWN state after CSS upgrade
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / impl / ItmProvider.java
1 /*
2  * Copyright (c) 2016, 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.impl;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import java.util.Collection;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Optional;
16 import java.util.concurrent.ExecutionException;
17 import java.util.regex.Matcher;
18 import java.util.regex.Pattern;
19 import javax.annotation.PostConstruct;
20 import javax.annotation.PreDestroy;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.apache.aries.blueprint.annotation.service.Service;
24 import org.opendaylight.genius.itm.api.IITMProvider;
25 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
26 import org.opendaylight.genius.itm.cache.TunnelStateCache;
27 import org.opendaylight.genius.itm.cli.TepCommandHelper;
28 import org.opendaylight.genius.itm.cli.TepException;
29 import org.opendaylight.genius.itm.diagstatus.ItmDiagStatusProvider;
30 import org.opendaylight.genius.itm.globals.ITMConstants;
31 import org.opendaylight.genius.itm.listeners.InterfaceStateListener;
32 import org.opendaylight.genius.itm.listeners.OvsdbNodeListener;
33 import org.opendaylight.genius.itm.listeners.TransportZoneListener;
34 import org.opendaylight.genius.itm.listeners.TunnelMonitorChangeListener;
35 import org.opendaylight.genius.itm.listeners.TunnelMonitorIntervalListener;
36 import org.opendaylight.genius.itm.monitoring.ItmTunnelEventListener;
37 import org.opendaylight.genius.itm.recovery.impl.EosChangeEventHandler;
38 import org.opendaylight.genius.itm.rpc.ItmManagerRpcService;
39 import org.opendaylight.infrautils.diagstatus.ServiceState;
40 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
41 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.binding.api.RpcProviderService;
44 import org.opendaylight.mdsal.common.api.ReadFailedException;
45 import org.opendaylight.mdsal.eos.binding.api.Entity;
46 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipCandidateRegistration;
47 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipChange;
48 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListener;
49 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipListenerRegistration;
50 import org.opendaylight.mdsal.eos.binding.api.EntityOwnershipService;
51 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolOutput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.config.rev160406.ItmConfig;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.AddExternalTunnelEndpointInputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.RemoveExternalTunnelEndpointInputBuilder;
65 import org.opendaylight.yangtools.yang.common.RpcResult;
66 import org.opendaylight.yangtools.yang.common.Uint32;
67 import org.opendaylight.yangtools.yang.common.Uint64;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 @Singleton
72 @Service
73 public class ItmProvider implements AutoCloseable, IITMProvider /*,ItmStateService */ {
74
75     private static final Logger LOG = LoggerFactory.getLogger(ItmProvider.class);
76
77     private final DataBroker dataBroker;
78     private final ItmManagerRpcService itmRpcService ;
79     private final IdManagerService idManager;
80     private final TepCommandHelper tepCommandHelper;
81     private final TransportZoneListener tzChangeListener;
82     private final TunnelMonitorChangeListener tnlToggleListener;
83     private final TunnelMonitorIntervalListener tnlIntervalListener;
84     private final InterfaceStateListener ifStateListener;
85     private final EntityOwnershipService entityOwnershipService;
86     private final ItmDiagStatusProvider itmStatusProvider;
87     private RpcProviderService rpcProviderService;
88     private final ItmTunnelEventListener itmStateListener;
89     private final OvsdbNodeListener ovsdbChangeListener;
90     static short flag = 0;
91     private final TunnelMonitoringConfig tunnelMonitoringConfig;
92     private EntityOwnershipCandidateRegistration registryCandidate;
93     private final DpnTepStateCache dpnTepStateCache;
94     private final TunnelStateCache tunnelStateCache;
95     private final ItmConfig itmConfig;
96     private final JobCoordinator jobCoordinator;
97     private final ItmProvider.ItmProviderEOSListener itmProviderEOSListener;
98     public  Integer batchSize;
99     public  Integer batchInterval;
100     private EosChangeEventHandler eosChangeEventHandler;
101
102     @Inject
103     public ItmProvider(DataBroker dataBroker,
104                        IdManagerService idManagerService,
105                        InterfaceStateListener interfaceStateListener,
106                        ItmManagerRpcService itmManagerRpcService,
107                        ItmTunnelEventListener itmTunnelEventListener,
108                        TepCommandHelper tepCommandHelper,
109                        TunnelMonitorChangeListener tunnelMonitorChangeListener,
110                        TunnelMonitorIntervalListener tunnelMonitorIntervalListener,
111                        TransportZoneListener transportZoneListener,
112                        OvsdbNodeListener ovsdbNodeListener,
113                        TunnelMonitoringConfig tunnelMonitoringConfig,
114                        EntityOwnershipService entityOwnershipService,
115                        DpnTepStateCache dpnTepStateCache,
116                        final ItmDiagStatusProvider itmDiagStatusProvider,
117                        final TunnelStateCache tunnelStateCache,
118                        final ItmConfig itmConfig,
119                        final JobCoordinator jobCoordinator,
120                        final EosChangeEventHandler eosChangeEventHandler) {
121         LOG.info("ItmProvider Before register MBean");
122         this.dataBroker = dataBroker;
123         this.idManager = idManagerService;
124         this.ifStateListener = interfaceStateListener;
125         this.itmRpcService = itmManagerRpcService;
126         this.itmStateListener = itmTunnelEventListener;
127         this.tepCommandHelper = tepCommandHelper;
128         this.tnlToggleListener = tunnelMonitorChangeListener;
129         this.tnlIntervalListener = tunnelMonitorIntervalListener;
130         this.tzChangeListener = transportZoneListener;
131         this.ovsdbChangeListener = ovsdbNodeListener;
132         this.tunnelMonitoringConfig = tunnelMonitoringConfig;
133         this.entityOwnershipService = entityOwnershipService;
134         this.dpnTepStateCache = dpnTepStateCache;
135         this.itmStatusProvider = itmDiagStatusProvider;
136         this.tunnelStateCache = tunnelStateCache;
137         this.eosChangeEventHandler = eosChangeEventHandler;
138
139         this.itmConfig = itmConfig;
140         this.jobCoordinator = jobCoordinator;
141         this.itmProviderEOSListener = new ItmProvider.ItmProviderEOSListener(this, this.entityOwnershipService);
142     }
143
144     @PostConstruct
145     @SuppressWarnings("checkstyle:IllegalCatch")
146     public void start() {
147         try {
148             createIdPool();
149             registerEntityForOwnership();
150             initialiseBatchingManager();
151             LOG.info("ItmProvider Started");
152         } catch (Exception ex) {
153             itmStatusProvider.reportStatus(ex);
154             LOG.info("ItmProvider failed to start", ex);
155             return;
156         }
157     }
158
159     public void initialiseBatchingManager() {
160         batchSize = ITMConstants.BATCH_SIZE;
161         LOG.info("entered initialse");
162         if (itmConfig.getBatchSize() != null) {
163             batchSize = itmConfig.getBatchSize().toJava();
164         }
165         batchInterval = ITMConstants.PERIODICITY;
166         if (itmConfig.getBatchInterval() != null) {
167             batchInterval = itmConfig.getBatchInterval().toJava();
168         }
169         ITMBatchingUtils.registerWithBatchManager(this.dataBroker,this.batchSize,this.batchInterval);
170     }
171
172     public void createDefaultTransportZone(ItmConfig itmConfigObj) {
173         jobCoordinator.enqueueJob(ITMConstants.DEFAULT_TRANSPORT_ZONE, () -> {
174             boolean defTzEnabled = itmConfigObj.isDefTzEnabled();
175             if (defTzEnabled) {
176                 String tunnelType = itmConfigObj.getDefTzTunnelType();
177                 if (tunnelType == null || tunnelType.isEmpty()) {
178                     tunnelType = ITMConstants.TUNNEL_TYPE_VXLAN;
179                 }
180                 // validate tunnel-type and based on tunnel-type,
181                 // create default-TZ or update default-TZ if tunnel-type is changed during ODL restart
182                 configureTunnelType(ITMConstants.DEFAULT_TRANSPORT_ZONE, tunnelType);
183                 LOG.info("{} is created with {} tunnel-type.", ITMConstants.DEFAULT_TRANSPORT_ZONE, tunnelType);
184             } else {
185                 LOG.info("Removing {} on start-up, def-tz-enabled is false.", ITMConstants.DEFAULT_TRANSPORT_ZONE);
186                 // check if default-TZ already exists, then delete it because flag is OFF now.
187                 ItmUtils.deleteTransportZoneFromConfigDS(ITMConstants.DEFAULT_TRANSPORT_ZONE, dataBroker);
188             }
189             return Collections.emptyList();
190         });
191     }
192
193     private void registerEntityForOwnership() {
194         try {
195             this.registryCandidate = entityOwnershipService
196                     .registerCandidate(new Entity(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY));
197         } catch (CandidateAlreadyRegisteredException e) {
198             LOG.error("failed to register entity {} for entity-ownership-service", e.getEntity());
199         }
200     }
201
202     @Override
203     @PreDestroy
204     public void close() {
205         if (tzChangeListener != null) {
206             tzChangeListener.close();
207         }
208         if (tnlIntervalListener != null) {
209             tnlIntervalListener.close();
210         }
211         if (tnlToggleListener != null) {
212             tnlToggleListener.close();
213         }
214         if (ovsdbChangeListener != null) {
215             ovsdbChangeListener.close();
216         }
217         if (registryCandidate != null) {
218             registryCandidate.close();
219         }
220         itmStatusProvider.reportStatus(ServiceState.UNREGISTERED);
221         this.itmProviderEOSListener.close();
222         LOG.info("ItmProvider Closed");
223     }
224
225     private void createIdPool() {
226         CreateIdPoolInput createPool = new CreateIdPoolInputBuilder()
227                 .setPoolName(ITMConstants.ITM_IDPOOL_NAME)
228                 .setLow(ITMConstants.ITM_IDPOOL_START)
229                 .setHigh(Uint32.valueOf(ITMConstants.ITM_IDPOOL_SIZE))
230                 .build();
231         try {
232             ListenableFuture<RpcResult<CreateIdPoolOutput>> result = idManager.createIdPool(createPool);
233             if (result != null && result.get().isSuccessful()) {
234                 LOG.debug("Created IdPool for ITM Service");
235             }
236         } catch (InterruptedException | ExecutionException e) {
237             LOG.error("Failed to create idPool for ITM Service ", e);
238         }
239     }
240
241     @Override
242     public DataBroker getDataBroker() {
243         return dataBroker;
244     }
245
246     @Override
247     public void addExternalEndpoint(Class<? extends TunnelTypeBase> tunnelType, IpAddress dcgwIP) {
248         AddExternalTunnelEndpointInput addExternalTunnelEndpointInput =
249                 new AddExternalTunnelEndpointInputBuilder().setTunnelType(tunnelType)
250                         .setDestinationIp(dcgwIP).build();
251         LoggingFutures.addErrorLogging(itmRpcService.addExternalTunnelEndpoint(addExternalTunnelEndpointInput),
252                 LOG, "addExternalTunnelEndpoint");
253     }
254
255     @Override
256     public void remExternalEndpoint(Class<? extends TunnelTypeBase> tunnelType, IpAddress dcgwIP) {
257         RemoveExternalTunnelEndpointInput removeExternalTunnelEndpointInput =
258                 new RemoveExternalTunnelEndpointInputBuilder().setTunnelType(tunnelType)
259                         .setDestinationIp(dcgwIP).build();
260         LoggingFutures.addErrorLogging(itmRpcService.removeExternalTunnelEndpoint(removeExternalTunnelEndpointInput),
261                 LOG, "removeExternalTunnelEndpoint");
262     }
263
264     @Override
265     public void createLocalCache(Uint64 dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
266             String gatewayIp, String transportZone) {
267         if (tepCommandHelper != null) {
268             try {
269                 tepCommandHelper.createLocalCache(dpnId, ipAddress, transportZone);
270             } catch (TepException e) {
271                 LOG.error("Create Local Cache failed", e);
272             }
273         } else {
274             LOG.trace("tepCommandHelper doesnt exist");
275         }
276     }
277
278     @Override
279     public void commitTeps() {
280         tepCommandHelper.deleteOnCommit();
281         tepCommandHelper.buildTeps();
282     }
283
284     @Override
285     public List<String> showTeps() {
286         try {
287             return tepCommandHelper.showTeps(tunnelMonitoringConfig.isTunnelMonitoringEnabled(),
288                     tunnelMonitoringConfig.getMonitorInterval());
289         } catch (TepException e) {
290             LOG.error("show teps failed", e);
291             return Collections.singletonList(e.getMessage());
292         }
293     }
294
295     @Override
296     public void showState(Collection<StateTunnelList> tunnels) {
297         if (tunnels != null) {
298             try {
299                 tepCommandHelper.showState(tunnels, tunnelMonitoringConfig.isTunnelMonitoringEnabled());
300             } catch (TepException e) {
301                 LOG.error("show state failed", e);
302             }
303         } else {
304             LOG.debug("No tunnels available");
305         }
306     }
307
308     @Override
309     public void showBridges(Map dpnIdBridgeRefsMap) {
310         if (!dpnIdBridgeRefsMap.isEmpty()) {
311             tepCommandHelper.showBridges(dpnIdBridgeRefsMap);
312         } else {
313             LOG.warn("tep:show-bridges => No bridges available");
314         }
315     }
316
317     @Override
318     public void showCache(String cacheName) {
319         tepCommandHelper.showCache(cacheName);
320     }
321
322     @Override
323     public void deleteVtep(Uint64 dpnId, String portName, Integer vlanId, String ipAddress, String subnetMask,
324             String gatewayIp, String transportZone) {
325         try {
326             tepCommandHelper.deleteVtep(dpnId, ipAddress, transportZone);
327         } catch (TepException e) {
328             LOG.error("Delete Vteps Failed", e);
329         }
330     }
331
332     @Override
333     public void configureTunnelType(String transportZone, String tunnelType) {
334         LOG.debug("ItmProvider: configureTunnelType {} for transportZone {}", tunnelType, transportZone);
335         try {
336             tepCommandHelper.configureTunnelType(transportZone,tunnelType);
337         } catch (ExecutionException | InterruptedException e) {
338             LOG.error("configureTunnelType {} failed for transportZone {}", tunnelType, transportZone, e);
339         }
340     }
341
342     @Override
343     public void configureTunnelMonitorParams(boolean monitorEnabled, String monitorProtocol) {
344         tepCommandHelper.configureTunnelMonitorParams(monitorEnabled, monitorProtocol);
345     }
346
347     @Override
348     public void configureTunnelMonitorInterval(int interval) {
349         tepCommandHelper.configureTunnelMonitorInterval(interval);
350     }
351
352     @Override
353     public boolean validateIP(final String ip) {
354         if (ip == null || ip.isEmpty() || "null".equals(ip) || "0.0.0.0".equals(ip)) {
355             return false;
356         }
357         final String PTRN =
358                 "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
359         Pattern pattern = Pattern.compile(PTRN);
360         Matcher matcher = pattern.matcher(ip);
361         return matcher.matches();
362     }
363
364     @Override
365     public Interface getInterface(String tunnelName) {
366         return dpnTepStateCache.getInterfaceFromCache(tunnelName);
367     }
368
369     @Override
370     public Optional<StateTunnelList> getTunnelState(String interfaceName) throws ReadFailedException {
371         return tunnelStateCache.get(tunnelStateCache.getStateTunnelListIdentifier(interfaceName));
372     }
373
374     public void handleOwnershipChange(EntityOwnershipChange ownershipChange,
375                                       EntityOwnershipListenerRegistration listenerRegistration) {
376         if (ownershipChange.getState().isOwner()) {
377             LOG.info("*This* instance of provider is set as a MASTER instance");
378             createDefaultTransportZone(itmConfig);
379             eosChangeEventHandler.recoverUnknownTunnelsOnEosSwitch();
380         } else {
381             LOG.info("*This* instance of provider is set as a SLAVE instance");
382         }
383         itmStatusProvider.reportStatus(ServiceState.OPERATIONAL);
384         if (listenerRegistration != null) {
385             listenerRegistration.close();
386         }
387     }
388
389     private static class ItmProviderEOSListener implements EntityOwnershipListener {
390         private final ItmProvider itmProviderObj;
391         private final EntityOwnershipListenerRegistration listenerRegistration;
392
393         ItmProviderEOSListener(ItmProvider itmProviderObj, EntityOwnershipService entityOwnershipService) {
394             this.itmProviderObj = itmProviderObj;
395             this.listenerRegistration = entityOwnershipService.registerListener(ITMConstants.ITM_CONFIG_ENTITY, this);
396         }
397
398         public void close() {
399             listenerRegistration.close();
400         }
401
402         @Override
403         public void ownershipChanged(EntityOwnershipChange ownershipChange) {
404             itmProviderObj.handleOwnershipChange(ownershipChange, listenerRegistration);
405         }
406     }
407 }