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