MRI version bump for Aluminium
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / itmdirecttunnels / listeners / TerminationPointStateListener.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.itmdirecttunnels.listeners;
9
10 import com.google.common.util.concurrent.ListenableFuture;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
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.Callable;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
20 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
21 import org.opendaylight.genius.itm.cache.BfdStateCache;
22 import org.opendaylight.genius.itm.cache.DpnTepStateCache;
23 import org.opendaylight.genius.itm.cache.TunnelStateCache;
24 import org.opendaylight.genius.itm.globals.ITMConstants;
25 import org.opendaylight.genius.itm.impl.ItmUtils;
26 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
27 import org.opendaylight.genius.utils.clustering.EntityOwnershipUtils;
28 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
29 import org.opendaylight.mdsal.binding.api.DataBroker;
30 import org.opendaylight.mdsal.binding.api.WriteTransaction;
31 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
32 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredSyncDataTreeChangeListener;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatus;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceBfdStatusKey;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class TerminationPointStateListener
50         extends AbstractClusteredSyncDataTreeChangeListener<OvsdbTerminationPointAugmentation> {
51
52     private static final Logger LOG = LoggerFactory.getLogger(TerminationPointStateListener.class);
53     private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
54
55     private final ManagedNewTransactionRunner txRunner;
56     private final EntityOwnershipUtils entityOwnershipUtils;
57     private final JobCoordinator coordinator;
58     private final BfdStateCache bfdStateCache;
59     private final DpnTepStateCache dpnTepStateCache;
60     private final TunnelStateCache tunnelStateCache;
61
62     public TerminationPointStateListener(final DataBroker dataBroker, final EntityOwnershipUtils entityOwnershipUtils,
63                                          final JobCoordinator coordinator, final BfdStateCache bfdStateCache,
64                                          final DpnTepStateCache dpnTepStateCache,
65                                          final TunnelStateCache tunnelStateCache) {
66         super(dataBroker, LogicalDatastoreType.OPERATIONAL,
67                 InstanceIdentifier.create(NetworkTopology.class).child(Topology.class).child(Node.class)
68                         .child(TerminationPoint.class).augmentation(OvsdbTerminationPointAugmentation.class));
69         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
70         this.entityOwnershipUtils = entityOwnershipUtils;
71         this.coordinator = coordinator;
72         this.bfdStateCache = bfdStateCache;
73         this.dpnTepStateCache = dpnTepStateCache;
74         this.tunnelStateCache = tunnelStateCache;
75         super.register();
76     }
77
78     @Override
79     public void remove(@NonNull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
80                        @NonNull OvsdbTerminationPointAugmentation tpOld) {
81         if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpOld.getName())
82                 && dpnTepStateCache.isInternal(tpOld.getName())) {
83             LOG.debug("Received remove DataChange Notification for ovsdb termination point {}", tpOld.getName());
84             if (tpOld.getInterfaceBfdStatus() != null) {
85                 LOG.debug("Received termination point removed notification with bfd status values {}", tpOld.getName());
86                 RendererTunnelStateRemoveWorker rendererStateRemoveWorker = new RendererTunnelStateRemoveWorker(tpOld);
87                 coordinator.enqueueJob(tpOld.getName(), rendererStateRemoveWorker);
88             }
89         }
90     }
91
92     @Override
93     public void update(@NonNull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
94                        @NonNull OvsdbTerminationPointAugmentation tpOld,
95                        @NonNull OvsdbTerminationPointAugmentation tpNew) {
96         if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpNew.getName())
97                 && dpnTepStateCache.isInternal(tpNew.getName())) {
98             LOG.debug("Received Update DataChange Notification for ovsdb termination point {}", tpNew.getName());
99             if (DirectTunnelUtils.changeInBfdMonitoringDetected(tpOld, tpNew)
100                     || DirectTunnelUtils.ifBfdStatusNotEqual(tpOld, tpNew)) {
101                 EVENT_LOGGER.debug("ITM-TerminationPointState,UPDATE {}", tpNew.getName());
102                 LOG.info("Bfd Status changed for ovsdb termination point identifier: {},  old: {}, new: {}",
103                         identifier, tpOld, tpNew);
104                 RendererTunnelStateUpdateWorker rendererStateAddWorker = new RendererTunnelStateUpdateWorker(tpNew);
105                 coordinator.enqueueJob(tpNew.getName(), rendererStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
106             }
107         }
108     }
109
110     @Override
111     public void add(@NonNull InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
112                     @NonNull OvsdbTerminationPointAugmentation tpNew) {
113         if (DirectTunnelUtils.TUNNEL_PORT_PREDICATE.test(tpNew.getName())
114                 && dpnTepStateCache.isInternal(tpNew.getName())) {
115             LOG.debug("Received add DataChange Notification for ovsdb termination point {}", tpNew.getName());
116             if (tpNew.getInterfaceBfdStatus() != null  && !tpNew.getInterfaceBfdStatus().isEmpty()) {
117                 EVENT_LOGGER.debug("ITM-TerminationPointState,ADD {}", tpNew.getName());
118                 LOG.debug("Received termination point added notification with bfd status values {}", tpNew.getName());
119                 RendererTunnelStateUpdateWorker rendererStateUpdateWorker = new RendererTunnelStateUpdateWorker(tpNew);
120                 coordinator.enqueueJob(tpNew.getName(), rendererStateUpdateWorker, ITMConstants.JOB_MAX_RETRIES);
121             }
122         }
123     }
124
125     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
126             justification = "https://github.com/spotbugs/spotbugs/issues/811")
127     private List<ListenableFuture<Void>> updateTunnelState(OvsdbTerminationPointAugmentation terminationPointNew) {
128         final String interfaceName = terminationPointNew.getName();
129         final Interface.OperStatus interfaceBfdStatus = getTunnelOpState(terminationPointNew);
130         TunnelOperStatus tunnelState = DirectTunnelUtils.convertInterfaceToTunnelOperState(interfaceBfdStatus);
131         bfdStateCache.add(interfaceName, interfaceBfdStatus);
132         if (!entityOwnershipUtils.isEntityOwner(ITMConstants.ITM_CONFIG_ENTITY, ITMConstants.ITM_CONFIG_ENTITY)) {
133             return Collections.emptyList();
134         }
135
136         coordinator.enqueueJob(interfaceName, () -> {
137             // update opstate of interface if TEP has gone down/up as a result of BFD monitoring
138             Optional<StateTunnelList> stateTnl = tunnelStateCache.get(tunnelStateCache
139                     .getStateTunnelListIdentifier(interfaceName));
140             if (stateTnl.isPresent() && stateTnl.get().getOperState() != TunnelOperStatus.Unknown
141                     && stateTnl.get().getOperState() != tunnelState) {
142                 LOG.debug("updating tunnel state for interface {} as {}", interfaceName,
143                         stateTnl.get().getOperState());
144                 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
145                     tx -> updateOpState(tx, interfaceName, tunnelState)));
146             }
147             return Collections.emptyList();
148         });
149         return Collections.emptyList();
150     }
151
152     private Interface.OperStatus getTunnelOpState(OvsdbTerminationPointAugmentation terminationPoint) {
153         if (!DirectTunnelUtils.bfdMonitoringEnabled(terminationPoint.getInterfaceBfd())) {
154             return Interface.OperStatus.Up;
155         }
156         @Nullable Map<InterfaceBfdStatusKey, InterfaceBfdStatus> tunnelBfdStatus =
157                 terminationPoint.getInterfaceBfdStatus();
158         if (tunnelBfdStatus != null && !tunnelBfdStatus.isEmpty()) {
159             for (InterfaceBfdStatus bfdState : tunnelBfdStatus.values()) {
160                 if (DirectTunnelUtils.BFD_OP_STATE.equalsIgnoreCase(bfdState.getBfdStatusKey())) {
161                     String bfdOpState = bfdState.getBfdStatusValue();
162                     return DirectTunnelUtils.BFD_STATE_UP.equalsIgnoreCase(bfdOpState)
163                             ? Interface.OperStatus.Up : Interface.OperStatus.Down;
164                 }
165             }
166         }
167         return Interface.OperStatus.Down;
168     }
169
170     /*
171      * update operational state of interface based on events like tunnel
172      * monitoring
173      */
174     private static void updateOpState(WriteTransaction transaction, String interfaceName, TunnelOperStatus operStatus) {
175         StateTunnelListKey stateTnlKey = new StateTunnelListKey(interfaceName);
176         InstanceIdentifier<StateTunnelList> stateTnlII = ItmUtils.buildStateTunnelListId(stateTnlKey);
177         LOG.debug("updating tep interface state as {} for {}", operStatus.name(), interfaceName);
178         StateTunnelListBuilder stateTnlBuilder = new StateTunnelListBuilder().withKey(stateTnlKey);
179         stateTnlBuilder.setOperState(operStatus);
180         transaction.mergeParentStructureMerge(LogicalDatastoreType.OPERATIONAL, stateTnlII, stateTnlBuilder.build());
181     }
182
183     private class RendererTunnelStateUpdateWorker implements Callable<List<? extends ListenableFuture<?>>> {
184         private final OvsdbTerminationPointAugmentation terminationPointNew;
185
186         RendererTunnelStateUpdateWorker(OvsdbTerminationPointAugmentation tpNew) {
187             this.terminationPointNew = tpNew;
188         }
189
190         @Override
191         public List<ListenableFuture<Void>> call() throws Exception {
192             // If another renderer(for eg : OVS) needs to be supported, check can be performed here
193             // to call the respective helpers.
194             return updateTunnelState(terminationPointNew);
195         }
196     }
197
198     private class RendererTunnelStateRemoveWorker implements Callable<List<? extends ListenableFuture<?>>> {
199         private final OvsdbTerminationPointAugmentation terminationPointOld;
200
201         RendererTunnelStateRemoveWorker(OvsdbTerminationPointAugmentation tpNew) {
202             this.terminationPointOld = tpNew;
203         }
204
205         @Override
206         public List<ListenableFuture<Void>> call() throws Exception {
207             LOG.debug("Removing bfd state from cache, if any, for {}", terminationPointOld.getName());
208             bfdStateCache.remove(terminationPointOld.getName());
209             return Collections.emptyList();
210         }
211     }
212 }