2 * Copyright (c) 2017 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package io.fd.hc2vpp.v3po.interfacesstate.cache;
19 import static io.fd.hc2vpp.common.translate.util.JvppReplyConsumer.INSTANCE;
20 import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
21 import static java.util.stream.Collectors.toMap;
23 import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
24 import io.fd.hc2vpp.common.translate.util.NamingContext;
25 import io.fd.honeycomb.translate.ModificationCache;
26 import io.fd.honeycomb.translate.read.ReadContext;
27 import io.fd.honeycomb.translate.read.ReadFailedException;
28 import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
29 import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor;
30 import io.fd.honeycomb.translate.util.read.cache.StaticCacheKeyFactory;
31 import io.fd.vpp.jvpp.core.dto.SwInterfaceDetails;
32 import io.fd.vpp.jvpp.core.dto.SwInterfaceDetailsReplyDump;
33 import io.fd.vpp.jvpp.core.dto.SwInterfaceDump;
34 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
36 import java.util.concurrent.CompletableFuture;
37 import java.util.stream.Stream;
38 import javax.annotation.Nonnull;
39 import javax.annotation.Nullable;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * Manager for dump data of interfaces/sub-interfaces
47 final class InterfaceCacheDumpManagerImpl implements InterfaceCacheDumpManager {
49 private static final Logger LOG = LoggerFactory.getLogger(InterfaceCacheDumpManagerImpl.class);
51 // byNameIndex must be cached, not held as reference here, to have it destroyed with cache after transaction
52 static final String BY_NAME_INDEX_KEY = InterfaceCacheDumpManagerImpl.class.getName() + "_byNameIndex";
53 private NamingContext namingContext;
54 private final DumpCacheManager<SwInterfaceDetailsReplyDump, String> specificDumpManager;
55 private final DumpCacheManager<SwInterfaceDetailsReplyDump, Void> fullDumpManager;
57 InterfaceCacheDumpManagerImpl(@Nonnull final FutureJVppCore jvpp,
58 @Nonnull final NamingContext namingContext) {
59 this.namingContext = namingContext;
60 specificDumpManager = specificInterfaceDumpManager(jvpp);
61 fullDumpManager = fullInterfaceDumpManager(jvpp,
62 new StaticCacheKeyFactory(InterfaceCacheDumpManagerImpl.class.getName() + "_dump", SwInterfaceDetailsReplyDump.class));
67 public synchronized Stream<SwInterfaceDetails> getInterfaces(@Nonnull final InstanceIdentifier<?> identifier,
68 @Nonnull final ReadContext ctx)
69 throws ReadFailedException {
70 LOG.debug("Reading all interfaces[{}]", identifier);
71 return initMapAndGet(identifier, ctx).entrySet().stream().map(Map.Entry::getValue);
76 public synchronized SwInterfaceDetails getInterfaceDetail(@Nonnull final InstanceIdentifier<?> identifier,
77 @Nonnull final ReadContext ctx,
78 @Nonnull final String interfaceName)
79 throws ReadFailedException {
80 final Map<String, SwInterfaceDetails> interfaceIndex = getMap(ctx);
82 // does not attempt to cover cases with concurrent updates, as tx should be atomic
83 if (interfaceIndex != null) {
84 // tries to find interface in map
85 return interfaceIndex.get(interfaceName);
87 // if map is not present, use specific dump(it will be cached standard way, under key constructed from IID)
88 return dumpSpecificDetail(identifier, ctx, interfaceName);
92 private SwInterfaceDetails dumpSpecificDetail(@Nonnull final InstanceIdentifier<?> identifier,
93 @Nonnull final ReadContext ctx,
94 @Nonnull final String interfaceName)
95 throws ReadFailedException {
96 LOG.debug("Interface {} not present in cached data, performing specific dump[{}]", interfaceName,
98 final SwInterfaceDetailsReplyDump reply =
99 specificDumpManager.getDump(identifier, ctx.getModificationCache(), interfaceName)
100 .or(new SwInterfaceDetailsReplyDump());
102 if (reply.swInterfaceDetails.isEmpty()) {
106 return reply.swInterfaceDetails.get(0);
109 private Map<String, SwInterfaceDetails> initMapAndGet(final InstanceIdentifier<?> identifier, final ReadContext ctx)
110 throws ReadFailedException {
112 final ModificationCache cache = ctx.getModificationCache();
113 if (!cache.containsKey(BY_NAME_INDEX_KEY)) {
114 LOG.debug("Performing dump[{}]", identifier);
115 final SwInterfaceDetailsReplyDump dump =
116 fullDumpManager.getDump(identifier, cache, NO_PARAMS)
117 .or(new SwInterfaceDetailsReplyDump());
119 // naming context initialization must be done here, as it is uses getName in next step, therefore it would
120 // create artificial mapping for every interface, because this happens before interface dump is processed
121 dump.swInterfaceDetails.forEach((elt) -> {
122 // Store interface name from VPP in context if not yet present
123 if (!namingContext.containsName(elt.swIfIndex, ctx.getMappingContext())) {
124 namingContext.addName(elt.swIfIndex, ByteDataTranslator.INSTANCE.toString(elt.interfaceName),
125 ctx.getMappingContext());
127 LOG.trace("Interface with name: {}, VPP name: {} and index: {} found in VPP",
128 getInterfaceName(ctx, elt),
133 final Map<String, SwInterfaceDetails> freshIndex = dump.swInterfaceDetails.stream()
134 .collect(toMap(detail -> getInterfaceName(ctx, detail),
136 putMap(freshIndex, ctx);
142 private String getInterfaceName(final ReadContext ctx, final SwInterfaceDetails elt) {
143 return namingContext.getName(elt.swIfIndex, ctx.getMappingContext());
146 private static Map<String, SwInterfaceDetails> getMap(final ReadContext ctx) {
147 return (Map<String, SwInterfaceDetails>) ctx.getModificationCache().get(BY_NAME_INDEX_KEY);
150 private static void putMap(final Map<String, SwInterfaceDetails> map, final ReadContext ctx) {
151 ctx.getModificationCache().put(BY_NAME_INDEX_KEY, map);
155 private static DumpCacheManager<SwInterfaceDetailsReplyDump, Void> fullInterfaceDumpManager(
156 final FutureJVppCore jvpp,
157 final StaticCacheKeyFactory cacheKeyFactory) {
158 return new DumpCacheManager.DumpCacheManagerBuilder<SwInterfaceDetailsReplyDump, Void>()
159 .withExecutor(fullInterfaceDumpExecutor(jvpp))
160 .withCacheKeyFactory(cacheKeyFactory)
161 .acceptOnly(SwInterfaceDetailsReplyDump.class)
165 private static DumpCacheManager<SwInterfaceDetailsReplyDump, String> specificInterfaceDumpManager(
166 final FutureJVppCore jvpp) {
167 return new DumpCacheManager.DumpCacheManagerBuilder<SwInterfaceDetailsReplyDump, String>()
168 .withExecutor(specificInterfaceDumpExecutor(jvpp))
169 .acceptOnly(SwInterfaceDetailsReplyDump.class)
173 private static EntityDumpExecutor<SwInterfaceDetailsReplyDump, Void> fullInterfaceDumpExecutor(
174 final FutureJVppCore api) {
175 return (identifier, params) -> {
176 final SwInterfaceDump request = new SwInterfaceDump();
177 request.nameFilter = "".getBytes();
178 request.nameFilterValid = 0;
180 final CompletableFuture<SwInterfaceDetailsReplyDump>
181 swInterfaceDetailsReplyDumpCompletableFuture = api.swInterfaceDump(request).toCompletableFuture();
182 return INSTANCE.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, identifier);
186 private static EntityDumpExecutor<SwInterfaceDetailsReplyDump, String> specificInterfaceDumpExecutor(
187 final FutureJVppCore api) {
188 return (identifier, ifaceName) -> {
189 final SwInterfaceDump request = new SwInterfaceDump();
190 request.nameFilter = ifaceName.getBytes();
191 request.nameFilterValid = 1;
193 final CompletableFuture<SwInterfaceDetailsReplyDump>
194 swInterfaceDetailsReplyDumpCompletableFuture = api.swInterfaceDump(request).toCompletableFuture();
195 return INSTANCE.getReplyForRead(swInterfaceDetailsReplyDumpCompletableFuture, identifier);