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.lisp.gpe.translate.read;
19 import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS;
20 import static java.lang.String.format;
22 import com.google.common.base.Optional;
23 import io.fd.hc2vpp.common.translate.util.FutureJVppCustomizer;
24 import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
25 import io.fd.hc2vpp.common.translate.util.NamingContext;
26 import io.fd.hc2vpp.lisp.gpe.translate.service.GpeStateCheckService;
27 import io.fd.hc2vpp.lisp.translate.read.dump.executor.params.MappingsDumpParams;
28 import io.fd.hc2vpp.lisp.translate.util.EidTranslator;
29 import io.fd.honeycomb.translate.ModificationCache;
30 import io.fd.honeycomb.translate.read.ReadContext;
31 import io.fd.honeycomb.translate.read.ReadFailedException;
32 import io.fd.honeycomb.translate.spi.read.Initialized;
33 import io.fd.honeycomb.translate.spi.read.InitializingListReaderCustomizer;
34 import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager;
35 import io.fd.vpp.jvpp.core.dto.GpeFwdEntriesGet;
36 import io.fd.vpp.jvpp.core.dto.GpeFwdEntriesGetReply;
37 import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetails;
38 import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDetailsReplyDump;
39 import io.fd.vpp.jvpp.core.dto.GpeFwdEntryPathDump;
40 import io.fd.vpp.jvpp.core.dto.GpeFwdEntryVnisGet;
41 import io.fd.vpp.jvpp.core.dto.GpeFwdEntryVnisGetReply;
42 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
43 import io.fd.vpp.jvpp.core.types.GpeFwdEntry;
44 import io.fd.vpp.jvpp.core.types.GpeLocator;
45 import java.util.Arrays;
46 import java.util.Collections;
47 import java.util.List;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
50 import javax.annotation.Nonnull;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.Gpe;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.GpeEntryTable;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.GpeEntryTableBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.GpeEntry;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.GpeEntryBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.entry.table.grouping.gpe.entry.table.GpeEntryKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.gpe.feature.data.grouping.GpeFeatureData;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.locator.pairs.grouping.LocatorPair;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.gpe.rev170801.locator.pairs.grouping.LocatorPairBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.lisp.rev170803.MapReplyAction;
61 import org.opendaylight.yangtools.concepts.Builder;
62 import org.opendaylight.yangtools.yang.binding.DataObject;
63 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
65 public class GpeForwardEntryCustomizer extends FutureJVppCustomizer
66 implements InitializingListReaderCustomizer<GpeEntry, GpeEntryKey, GpeEntryBuilder>, JvppReplyConsumer,
69 private final DumpCacheManager<GpeFwdEntriesGetReply, Integer> entryDumpManager;
70 private final DumpCacheManager<GpeFwdEntryPathDetailsReplyDump, Integer> entryDumpCacheManager;
71 private final DumpCacheManager<GpeFwdEntryVnisGetReply, Void> activeVnisDumpManager;
72 private final NamingContext gpeEntryMappingContext;
73 private final GpeStateCheckService gpeStateCheckService;
75 public GpeForwardEntryCustomizer(@Nonnull final FutureJVppCore futureJVppCore,
76 @Nonnull final GpeStateCheckService gpeStateCheckService,
77 @Nonnull final NamingContext gpeEntryMappingContext) {
78 super(futureJVppCore);
79 this.gpeStateCheckService = gpeStateCheckService;
80 this.gpeEntryMappingContext = gpeEntryMappingContext;
81 this.entryDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<GpeFwdEntriesGetReply, Integer>()
82 .acceptOnly(GpeFwdEntriesGetReply.class)
83 .withExecutor((identifier, vni) -> {
84 GpeFwdEntriesGet request = new GpeFwdEntriesGet();
86 return getReplyForRead(getFutureJVpp().gpeFwdEntriesGet(request).toCompletableFuture(), identifier);
88 entryDumpCacheManager =
89 new DumpCacheManager.DumpCacheManagerBuilder<GpeFwdEntryPathDetailsReplyDump, Integer>()
90 .acceptOnly(GpeFwdEntryPathDetailsReplyDump.class)
91 .withExecutor((identifier, fwdEntryIndex) -> {
92 GpeFwdEntryPathDump request = new GpeFwdEntryPathDump();
93 request.fwdEntryIndex = fwdEntryIndex;
94 return getReplyForRead(getFutureJVpp().gpeFwdEntryPathDump(request).toCompletableFuture(),
97 activeVnisDumpManager = new DumpCacheManager.DumpCacheManagerBuilder<GpeFwdEntryVnisGetReply, Void>()
98 .acceptOnly(GpeFwdEntryVnisGetReply.class)
99 .withExecutor((identifier, params) -> getReplyForRead(
100 getFutureJVpp().gpeFwdEntryVnisGet(new GpeFwdEntryVnisGet()).toCompletableFuture(),
107 public Initialized<? extends DataObject> init(@Nonnull final InstanceIdentifier<GpeEntry> id,
108 @Nonnull final GpeEntry readValue,
109 @Nonnull final ReadContext ctx) {
110 return Initialized.create(InstanceIdentifier.create(Gpe.class)
111 .child(GpeFeatureData.class)
112 .child(GpeEntryTable.class)
113 .child(GpeEntry.class, id.firstKeyOf(GpeEntry.class)), readValue);
118 public List<GpeEntryKey> getAllIds(@Nonnull final InstanceIdentifier<GpeEntry> id,
119 @Nonnull final ReadContext context)
120 throws ReadFailedException {
122 if (!gpeStateCheckService.isGpeEnabled(context)) {
123 return Collections.emptyList();
126 return activeVnis(id, context.getModificationCache())
127 .flatMap(vni -> getKeysForVni(id, vni, context).stream())
128 .collect(Collectors.toList());
132 public void merge(@Nonnull final Builder<? extends DataObject> builder, @Nonnull final List<GpeEntry> readData) {
133 ((GpeEntryTableBuilder) builder).setGpeEntry(readData);
138 public GpeEntryBuilder getBuilder(@Nonnull final InstanceIdentifier<GpeEntry> id) {
139 return new GpeEntryBuilder();
143 public void readCurrentAttributes(@Nonnull final InstanceIdentifier<GpeEntry> id,
144 @Nonnull final GpeEntryBuilder builder,
145 @Nonnull final ReadContext ctx) throws ReadFailedException {
146 if (!gpeStateCheckService.isGpeEnabled(ctx)) {
150 final String entryId = id.firstKeyOf(GpeEntry.class).getId();
152 // reads configured vni's, then reads entries for them and filter out current one
153 final java.util.Optional<GpeFwdEntry> entryCandicate = activeVnis(id, ctx.getModificationCache())
154 .flatMap(vni -> getEntriesForVni(id, vni, ctx).stream())
155 .filter(entry -> entryId
156 .equals(gpeEntryMappingContext.getName(entry.fwdEntryIndex, ctx.getMappingContext())))
159 if (entryCandicate.isPresent()) {
160 final GpeFwdEntry gpeFwdEntry = entryCandicate.get();
162 final int entryVni = gpeFwdEntry.vni;
164 if (!matchUndefinedEid(gpeFwdEntry.leid)) {
165 builder.setLocalEid(getArrayAsGpeLocalEid(MappingsDumpParams.EidType.valueOf(gpeFwdEntry.eidType),
166 gpeFwdEntry.leid, gpeFwdEntry.leidPrefixLen, entryVni));
169 builder.setId(entryId)
170 .setDpTable((long) gpeFwdEntry.dpTable)
171 .setRemoteEid(getArrayAsGpeRemoteEid(MappingsDumpParams.EidType.valueOf(gpeFwdEntry.eidType),
172 gpeFwdEntry.reid, gpeFwdEntry.reidPrefixLen, entryVni))
173 .setVni((long) entryVni);
175 final Optional<GpeFwdEntryPathDetailsReplyDump> locatorsDump =
176 entryDumpCacheManager.getDump(id, ctx.getModificationCache(), gpeFwdEntry.fwdEntryIndex);
178 // if any locators exist,it is a positive mapping
179 if (locatorsDump.isPresent() && locatorsDump.get().gpeFwdEntryPathDetails != null &&
180 !locatorsDump.get().gpeFwdEntryPathDetails.isEmpty()) {
181 final List<LocatorPair> pairs =
182 java.util.Optional.ofNullable(locatorsDump.get().gpeFwdEntryPathDetails)
183 .orElse(Collections.emptyList())
185 .map(entry -> buildLocatorPair(entry))
186 .collect(Collectors.toList());
187 builder.setLocatorPair(pairs);
189 // negative otherwise
190 builder.setAction(MapReplyAction.forValue(gpeFwdEntry.action));
195 // not matching by specifically sized array, easier to adapt if vpp going to change size of arrays they send
196 // addresses , because for lisp eid there are at least 3 possible sizes(v4 - 4,mac - 6,v6 - 16)
197 private static boolean matchUndefinedEid(byte[] addr) {
198 return addr == null || Arrays.equals(addr, new byte[addr.length]);
201 private List<GpeFwdEntry> getEntriesForVni(final InstanceIdentifier<GpeEntry> id, final int vni,
202 final ReadContext context) {
203 final Optional<GpeFwdEntriesGetReply> dump = getEntiesDump(id, vni, context);
204 if (dump.isPresent()) {
205 return Arrays.stream(java.util.Optional.ofNullable(dump.get().entries).orElse(new GpeFwdEntry[]{}))
206 .collect(Collectors.toList());
209 return Collections.emptyList();
212 private List<GpeEntryKey> getKeysForVni(final InstanceIdentifier<GpeEntry> id, final int vni,
213 final ReadContext context) {
215 final Optional<GpeFwdEntriesGetReply> dump = getEntiesDump(id, vni, context);
216 if (dump.isPresent()) {
217 return Arrays.stream(java.util.Optional.ofNullable(dump.get().entries).orElse(new GpeFwdEntry[]{}))
218 .map(entry -> gpeEntryMappingContext.getName(entry.fwdEntryIndex, context.getMappingContext()))
219 .map(GpeEntryKey::new)
220 .collect(Collectors.toList());
223 return Collections.emptyList();
226 private Optional<GpeFwdEntriesGetReply> getEntiesDump(final InstanceIdentifier<GpeEntry> id, final int vni,
227 final ReadContext context) {
228 final Optional<GpeFwdEntriesGetReply> dump;
230 dump = entryDumpManager.getDump(id, context.getModificationCache(), vni);
231 } catch (ReadFailedException e) {
232 throw new IllegalStateException(format("Unable to read Gpe entries for vni %s", vni), e);
237 private LocatorPair buildLocatorPair(final GpeFwdEntryPathDetails entry) {
238 final GpeLocator lclLoc = entry.lclLoc;
239 final GpeLocator rmtLoc = entry.rmtLoc;
240 return new LocatorPairBuilder()
241 .setLocalLocator(arrayToIpAddress(!byteToBoolean(lclLoc.isIp4), lclLoc.addr))
242 .setRemoteLocator(arrayToIpAddress(!byteToBoolean(rmtLoc.isIp4), rmtLoc.addr))
243 .setWeight((short) lclLoc.weight).build();
246 private Stream<Integer> activeVnis(final InstanceIdentifier<GpeEntry> id,
247 final ModificationCache cache) throws ReadFailedException {
248 final int[] vnis = activeVnisDumpManager.getDump(id, cache, NO_PARAMS).or(() -> {
249 final GpeFwdEntryVnisGetReply reply = new GpeFwdEntryVnisGetReply();
250 reply.vnis = new int[0];
253 return Arrays.stream(vnis).boxed();