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