9f1ae7a5bcd0a91b8e021a3060e77c8ff66761f8
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / cache / DpnTepStateCache.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.cache;
9
10 import java.util.Collection;
11 import java.util.Collections;
12 import java.util.List;
13 import java.util.Objects;
14 import java.util.concurrent.ConcurrentHashMap;
15 import java.util.concurrent.ConcurrentMap;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
25 import org.opendaylight.genius.itm.globals.ITMConstants;
26 import org.opendaylight.genius.itm.impl.ItmUtils;
27 import org.opendaylight.genius.itm.itmdirecttunnels.renderer.ovs.utilities.DirectTunnelUtils;
28 import org.opendaylight.genius.itm.itmdirecttunnels.workers.TunnelStateAddWorker;
29 import org.opendaylight.genius.itm.itmdirecttunnels.workers.TunnelStateAddWorkerForNodeConnector;
30 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfo;
31 import org.opendaylight.genius.itm.utils.DpnTepInterfaceInfoBuilder;
32 import org.opendaylight.genius.itm.utils.TunnelEndPointInfo;
33 import org.opendaylight.genius.itm.utils.TunnelEndPointInfoBuilder;
34 import org.opendaylight.genius.itm.utils.TunnelStateInfo;
35 import org.opendaylight.genius.itm.utils.TunnelStateInfoBuilder;
36 import org.opendaylight.genius.mdsalutil.cache.DataObjectCache;
37 import org.opendaylight.infrautils.caches.CacheProvider;
38 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
39 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.Acquired;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelMonitoringTypeBfd;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.DpnTepsState;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.endpoints.DPNTEPsInfo;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTeps;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.DpnsTepsKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpns;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.dpn.teps.state.dpns.teps.RemoteDpnsKey;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.Uint64;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 @Singleton
54 public class DpnTepStateCache extends DataObjectCache<Uint64, DpnsTeps> {
55
56     private static final Logger LOG = LoggerFactory.getLogger(DpnTepStateCache.class);
57     private static final Logger EVENT_LOGGER = LoggerFactory.getLogger("GeniusEventLogger");
58
59     private final DataBroker dataBroker;
60     private final JobCoordinator coordinator;
61     private final DirectTunnelUtils directTunnelUtils;
62     private final DPNTEPsInfoCache dpnTepsInfoCache;
63     private final UnprocessedNodeConnectorCache unprocessedNCCache;
64     private final UnprocessedNodeConnectorEndPointCache unprocessedNodeConnectorEndPointCache;
65     private final ManagedNewTransactionRunner txRunner;
66     private final ConcurrentMap<String, DpnTepInterfaceInfo> dpnTepInterfaceMap = new ConcurrentHashMap<>();
67     private final ConcurrentMap<String, TunnelEndPointInfo> tunnelEndpointMap = new ConcurrentHashMap<>();
68
69     @Inject
70     public DpnTepStateCache(DataBroker dataBroker, JobCoordinator coordinator,
71                             CacheProvider cacheProvider, DirectTunnelUtils directTunnelUtils,
72                             DPNTEPsInfoCache dpnTepsInfoCache,
73                             UnprocessedNodeConnectorCache unprocessedNCCache,
74                             UnprocessedNodeConnectorEndPointCache unprocessedNodeConnectorEndPointCache) {
75         super(DpnsTeps.class, dataBroker, LogicalDatastoreType.CONFIGURATION,
76             InstanceIdentifier.builder(DpnTepsState.class).child(DpnsTeps.class).build(), cacheProvider,
77             (iid, dpnsTeps) -> dpnsTeps.getSourceDpnId(),
78             sourceDpnId -> InstanceIdentifier.builder(DpnTepsState.class)
79                     .child(DpnsTeps.class, new DpnsTepsKey(sourceDpnId)).build());
80         this.dataBroker = dataBroker;
81         this.coordinator = coordinator;
82         this.directTunnelUtils = directTunnelUtils;
83         this.dpnTepsInfoCache = dpnTepsInfoCache;
84         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
85         this.unprocessedNCCache = unprocessedNCCache;
86         this.unprocessedNodeConnectorEndPointCache = unprocessedNodeConnectorEndPointCache;
87     }
88
89     @Override
90     protected void added(InstanceIdentifier<DpnsTeps> path, DpnsTeps dpnsTeps) {
91         String srcOfTunnel = dpnsTeps.getOfTunnel();
92         for (RemoteDpns remoteDpns : dpnsTeps.nonnullRemoteDpns()) {
93             final String dpn = getDpnId(dpnsTeps.getSourceDpnId(), remoteDpns.getDestinationDpnId());
94             DpnTepInterfaceInfo value = new DpnTepInterfaceInfoBuilder()
95                 .setTunnelName(remoteDpns.getTunnelName())
96                 .setIsMonitoringEnabled(remoteDpns.isMonitoringEnabled())
97                 .setIsInternal(remoteDpns.isInternal())
98                 .setTunnelType(dpnsTeps.getTunnelType())
99                 .setRemoteDPN(remoteDpns.getDestinationDpnId()).build();
100             dpnTepInterfaceMap.put(dpn, value);
101
102             addTunnelEndPointInfoToCache(remoteDpns.getTunnelName(), dpnsTeps.getSourceDpnId().toString(),
103                     remoteDpns.getDestinationDpnId().toString());
104
105             //Process the unprocessed NodeConnector for the Tunnel, if present in the UnprocessedNodeConnectorCache
106
107             TunnelStateInfo tunnelStateInfoNew = null;
108
109             TunnelStateInfo tunnelStateInfo;
110             try (Acquired lock = directTunnelUtils.lockTunnel(remoteDpns.getTunnelName())) {
111                 if (srcOfTunnel != null && unprocessedNCCache.get(dpn) != null) {
112                     tunnelStateInfo = unprocessedNCCache.remove(dpn);
113                 } else {
114                     tunnelStateInfo = unprocessedNCCache.remove(remoteDpns.getTunnelName());
115                 }
116             }
117
118             if (tunnelStateInfo != null) {
119                 LOG.debug("Processing the Unprocessed NodeConnector for Tunnel {}", remoteDpns.getTunnelName());
120
121                 TunnelEndPointInfo tunnelEndPtInfo = getTunnelEndPointInfo(dpnsTeps.getSourceDpnId().toString(),
122                         remoteDpns.getDestinationDpnId().toString());
123                 TunnelStateInfoBuilder builder = new TunnelStateInfoBuilder()
124                     .setNodeConnectorInfo(tunnelStateInfo.getNodeConnectorInfo()).setDpnTepInterfaceInfo(value)
125                     .setTunnelEndPointInfo(tunnelEndPtInfo);
126
127                 dpnTepsInfoCache.getDPNTepFromDPNId(dpnsTeps.getSourceDpnId()).ifPresent(builder::setSrcDpnTepsInfo);
128                 dpnTepsInfoCache.getDPNTepFromDPNId(remoteDpns.getDestinationDpnId())
129                     .ifPresent(builder::setDstDpnTepsInfo);
130
131                 tunnelStateInfoNew = builder.build();
132                 if (tunnelStateInfoNew.getSrcDpnTepsInfo() == null) {
133                     String srcDpnId = tunnelStateInfoNew.getTunnelEndPointInfo().getSrcEndPointInfo();
134                     try (Acquired lock = directTunnelUtils.lockTunnel(srcDpnId)) {
135                         LOG.debug("Source DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
136                             remoteDpns.getTunnelName(), srcDpnId);
137                         unprocessedNodeConnectorEndPointCache.add(srcDpnId, tunnelStateInfoNew);
138                     }
139                 }
140
141                 if (tunnelStateInfoNew.getDstDpnTepsInfo() == null) {
142                     String dstDpnId = tunnelStateInfoNew.getTunnelEndPointInfo().getDstEndPointInfo();
143                     try (Acquired lock = directTunnelUtils.lockTunnel(dstDpnId)) {
144                         LOG.debug("Destination DPNTepsInfo is null for tunnel {}. Hence Parking with key {}",
145                             remoteDpns.getTunnelName(), dstDpnId);
146                         unprocessedNodeConnectorEndPointCache.add(dstDpnId, tunnelStateInfoNew);
147                     }
148                 }
149             }
150
151             if (tunnelStateInfoNew != null && tunnelStateInfoNew.getSrcDpnTepsInfo() != null
152                 && tunnelStateInfoNew.getDstDpnTepsInfo() != null && directTunnelUtils.isEntityOwner()) {
153                 TunnelStateAddWorkerForNodeConnector ifStateAddWorker =
154                     new TunnelStateAddWorkerForNodeConnector(new TunnelStateAddWorker(directTunnelUtils, txRunner),
155                         tunnelStateInfoNew);
156                 EVENT_LOGGER.debug("ITM-DpnTepStateCache,ADD {}", remoteDpns.getTunnelName());
157                 coordinator.enqueueJob(remoteDpns.getTunnelName(), ifStateAddWorker, ITMConstants.JOB_MAX_RETRIES);
158             }
159         }
160     }
161
162     @Override
163     protected void removed(InstanceIdentifier<DpnsTeps> path, DpnsTeps dpnsTeps) {
164         for (RemoteDpns remoteDpns : dpnsTeps.nonnullRemoteDpns()) {
165             String fwkey = getDpnId(dpnsTeps.getSourceDpnId(), remoteDpns.getDestinationDpnId());
166             dpnTepInterfaceMap.remove(fwkey);
167             tunnelEndpointMap.remove(remoteDpns.getTunnelName());
168             String revkey = getDpnId(remoteDpns.getDestinationDpnId(), dpnsTeps.getSourceDpnId());
169             dpnTepInterfaceMap.remove(revkey);
170         }
171     }
172
173     private DpnTepInterfaceInfo getDpnTepInterface(String srcDpnId, String dstDpnId) {
174         return getDpnTepInterface(Uint64.valueOf(srcDpnId), Uint64.valueOf(dstDpnId));
175     }
176
177     public DpnTepInterfaceInfo getDpnTepInterface(Uint64 srcDpnId, Uint64 dstDpnId) {
178         DpnTepInterfaceInfo  dpnTepInterfaceInfo = dpnTepInterfaceMap.get(getDpnId(srcDpnId, dstDpnId));
179         if (dpnTepInterfaceInfo == null) {
180             try {
181                 com.google.common.base.Optional<DpnsTeps> dpnsTeps = super.get(srcDpnId);
182                 if (dpnsTeps.isPresent()) {
183                     DpnsTeps teps = dpnsTeps.get();
184                     teps.nonnullRemoteDpns().forEach(remoteDpns -> {
185                         DpnTepInterfaceInfo value = new DpnTepInterfaceInfoBuilder()
186                                 .setTunnelName(remoteDpns.getTunnelName())
187                                 .setIsMonitoringEnabled(remoteDpns.isMonitoringEnabled())
188                                 .setIsInternal(remoteDpns.isInternal())
189                                 .setTunnelType(teps.getTunnelType())
190                                 .setRemoteDPN(remoteDpns.getDestinationDpnId()).build();
191                         dpnTepInterfaceMap.putIfAbsent(getDpnId(srcDpnId, remoteDpns.getDestinationDpnId()), value);
192                         addTunnelEndPointInfoToCache(remoteDpns.getTunnelName(),
193                                 teps.getSourceDpnId().toString(), remoteDpns.getDestinationDpnId().toString());
194                         }
195                     );
196                 }
197             } catch (ReadFailedException e) {
198                 LOG.error("cache read for dpnID {} in DpnTepStateCache failed ", srcDpnId, e);
199             }
200         }
201         return dpnTepInterfaceMap.get(getDpnId(srcDpnId, dstDpnId));
202     }
203
204     public void removeTepFromDpnTepInterfaceConfigDS(Uint64 srcDpnId) throws TransactionCommitFailedException {
205         Collection<DpnsTeps> dpnsTeps = this.getAllPresent();
206         for (DpnsTeps dpnTep : dpnsTeps) {
207             if (!Objects.equals(dpnTep.getSourceDpnId(), srcDpnId)) {
208                 for (RemoteDpns remoteDpns : dpnTep.nonnullRemoteDpns()) {
209                     if (Objects.equals(remoteDpns.getDestinationDpnId(), srcDpnId)) {
210                         // Remote the SrcDpnId from the remote List. Remove it from COnfig DS. 4
211                         // This will be reflected in cache by the ClusteredDTCN. Not removing it here !
212                         //Caution :- Batching Delete !!
213                         InstanceIdentifier<RemoteDpns> remoteDpnII =
214                                 buildRemoteDpnsInstanceIdentifier(dpnTep.getSourceDpnId(),
215                                         remoteDpns.getDestinationDpnId());
216                         SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
217                                 remoteDpnII);
218                         break;
219                     }
220                 }
221             } else {
222                 // The source DPn id is the one to be removed
223                 InstanceIdentifier<DpnsTeps> dpnsTepsII
224                     = buildDpnsTepsInstanceIdentifier(dpnTep.getSourceDpnId());
225                 SingleTransactionDataBroker.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, dpnsTepsII);
226             }
227         }
228     }
229
230     private static InstanceIdentifier<DpnsTeps> buildDpnsTepsInstanceIdentifier(Uint64 srcDpnId) {
231         return InstanceIdentifier.builder(DpnTepsState.class).child(DpnsTeps.class, new DpnsTepsKey(srcDpnId)).build();
232     }
233
234     private static InstanceIdentifier<RemoteDpns> buildRemoteDpnsInstanceIdentifier(Uint64 srcDpnId, Uint64 dstDpnId) {
235         DpnsTepsKey dpnsTepsKey = new DpnsTepsKey(srcDpnId);
236         RemoteDpnsKey remoteDpnsKey = new RemoteDpnsKey(dstDpnId);
237         return InstanceIdentifier.builder(DpnTepsState.class).child(DpnsTeps.class, dpnsTepsKey)
238                 .child(RemoteDpns.class, remoteDpnsKey).build();
239     }
240
241     // Given the tunnel name find out if its internal or external
242     public boolean isInternal(String tunnelName) {
243         TunnelEndPointInfo endPointInfo = getTunnelEndPointInfoFromCache(tunnelName);
244         if (endPointInfo != null) {
245             DpnTepInterfaceInfo dpnTepInfo = getDpnTepInterface(endPointInfo.getSrcEndPointInfo(),
246                     endPointInfo.getDstEndPointInfo());
247             return dpnTepInfo != null && dpnTepInfo.isInternal();
248         }
249         return false;
250     }
251
252     public boolean isConfigAvailable(String tunnelName) {
253         TunnelEndPointInfo endPointInfo = getTunnelEndPointInfoFromCache(tunnelName);
254         if (endPointInfo != null) {
255             DpnTepInterfaceInfo dpnTepInfo = getDpnTepInterface(endPointInfo.getSrcEndPointInfo(),
256                     endPointInfo.getDstEndPointInfo());
257             return dpnTepInfo != null;
258         }
259         return false;
260     }
261
262     public DpnTepInterfaceInfo getTunnelFromCache(String tunnelName) {
263         TunnelEndPointInfo endPointInfo = getTunnelEndPointInfoFromCache(tunnelName);
264         return getDpnTepInterface(endPointInfo.getSrcEndPointInfo(), endPointInfo.getDstEndPointInfo());
265     }
266
267     // FIXME: this seems to be a cache key -- it should use a composite structure rather than string concat
268     private String getDpnId(Uint64 src, Uint64 dst) {
269         return src + ":" + dst;
270     }
271
272     public Interface getInterfaceFromCache(String tunnelName) {
273         TunnelEndPointInfo endPointInfo = getTunnelEndPointInfoFromCache(tunnelName);
274         Uint64 srcDpnId = Uint64.valueOf(endPointInfo.getSrcEndPointInfo());
275         Uint64 dstDpnId = Uint64.valueOf(endPointInfo.getDstEndPointInfo());
276         Interface iface = null ;
277         int monitoringInt = 1000;
278         DpnTepInterfaceInfo dpnTepInfo = getDpnTepInterface(srcDpnId, dstDpnId);
279         if (dpnTepInfo != null) {
280             List<DPNTEPsInfo> srcDpnTEPsInfo = dpnTepsInfoCache
281                     .getDPNTepListFromDPNId(Collections.singletonList(srcDpnId));
282             List<DPNTEPsInfo> dstDpnTEPsInfo = dpnTepsInfoCache
283                     .getDPNTepListFromDPNId(Collections.singletonList(dstDpnId));
284             iface = ItmUtils.buildTunnelInterface(srcDpnId, tunnelName,
285                     String.format("%s %s", ItmUtils.convertTunnelTypetoString(dpnTepInfo.getTunnelType()),
286                             "Trunk Interface"), true, dpnTepInfo.getTunnelType(),
287                     srcDpnTEPsInfo.get(0).getTunnelEndPoints().get(0).getIpAddress(),
288                     dstDpnTEPsInfo.get(0).getTunnelEndPoints().get(0).getIpAddress(),true,
289                     dpnTepInfo.isMonitoringEnabled(), TunnelMonitoringTypeBfd.class,
290                     monitoringInt, true, null);
291         }
292         return iface;
293     }
294
295     //Start: TunnelEndPoint Cache accessors
296     private void addTunnelEndPointInfoToCache(String tunnelName, String srcEndPtInfo, String dstEndPtInfo) {
297         tunnelEndpointMap.put(tunnelName, getTunnelEndPointInfo(srcEndPtInfo,dstEndPtInfo));
298     }
299
300     private TunnelEndPointInfo getTunnelEndPointInfo(String srcEndPtInfo, String dstEndPtInfo) {
301         return
302             new TunnelEndPointInfoBuilder().setSrcEndPointInfo(srcEndPtInfo).setDstEndPointInfo(dstEndPtInfo).build();
303     }
304
305     public TunnelEndPointInfo getTunnelEndPointInfoFromCache(String tunnelName) {
306         return tunnelEndpointMap.get(tunnelName);
307     }
308
309     public void removeFromTunnelEndPointMap(String tunnelName) {
310         tunnelEndpointMap.remove(tunnelName);
311     }
312 }