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