2 * Copyright (c) 2016 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.honeycomb.translate.v3po.vppclassifier;
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.base.Preconditions.checkState;
22 import static io.fd.honeycomb.translate.v3po.interfacesstate.InterfaceUtils.printHexBinary;
24 import com.google.common.base.Optional;
25 import com.google.common.primitives.UnsignedInts;
26 import io.fd.honeycomb.translate.MappingContext;
27 import io.fd.honeycomb.translate.read.ReadContext;
28 import io.fd.honeycomb.translate.read.ReadFailedException;
29 import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer;
30 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
31 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.List;
35 import java.util.stream.Collectors;
36 import javax.annotation.Nonnull;
37 import javax.annotation.Nullable;
38 import javax.xml.bind.DatatypeConverter;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.OpaqueIndex;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppNode;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySession;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.classify.table.base.attributes.ClassifySessionKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTable;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.state.ClassifyTableKey;
48 import org.opendaylight.yangtools.concepts.Builder;
49 import org.opendaylight.yangtools.yang.binding.DataObject;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.openvpp.jvpp.VppBaseCallException;
52 import org.openvpp.jvpp.core.dto.ClassifySessionDetails;
53 import org.openvpp.jvpp.core.dto.ClassifySessionDetailsReplyDump;
54 import org.openvpp.jvpp.core.dto.ClassifySessionDump;
55 import org.openvpp.jvpp.core.future.FutureJVppCore;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
60 * Reader customizer responsible for classify session read.<br> to VPP.<br> Equivalent to invoking {@code vppctl show
61 * class table verbose} command.
63 public class ClassifySessionReader extends FutureJVppCustomizer
64 implements ListReaderCustomizer<ClassifySession, ClassifySessionKey, ClassifySessionBuilder>, VppNodeReader {
66 private static final Logger LOG = LoggerFactory.getLogger(ClassifySessionReader.class);
67 static final String CACHE_KEY = ClassifySessionReader.class.getName();
69 private final VppClassifierContextManager classifyTableContext;
71 public ClassifySessionReader(@Nonnull final FutureJVppCore futureJVppCore,
72 @Nonnull final VppClassifierContextManager classifyTableContext) {
73 super(futureJVppCore);
74 this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
78 public void merge(@Nonnull final Builder<? extends DataObject> builder,
79 @Nonnull final List<ClassifySession> readData) {
80 ((ClassifyTableBuilder) builder).setClassifySession(readData);
85 public ClassifySessionBuilder getBuilder(@Nonnull final InstanceIdentifier<ClassifySession> id) {
86 return new ClassifySessionBuilder();
90 public void readCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifySession> id,
91 @Nonnull final ClassifySessionBuilder builder, @Nonnull final ReadContext ctx)
92 throws ReadFailedException {
93 LOG.debug("Reading attributes for classify session: {}", id);
95 final ClassifySessionKey key = id.firstKeyOf(ClassifySession.class);
96 checkArgument(key != null, "could not find ClassifySession key in {}", id);
98 final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
99 final byte[] match = DatatypeConverter.parseHexBinary(key.getMatch().getValue().replace(":", ""));
100 final Optional<ClassifySessionDetails> classifySession =
101 findClassifySessionDetailsByMatch(classifySessionDump, match);
103 if (classifySession.isPresent()) {
104 final ClassifySessionDetails detail = classifySession.get();
106 readVppNode(detail.tableId, detail.hitNextIndex, classifyTableContext, ctx.getMappingContext(), LOG).get());
107 if (detail.opaqueIndex != ~0) {
108 // value is specified:
109 builder.setOpaqueIndex(readOpaqueIndex(detail.tableId, detail.opaqueIndex, ctx.getMappingContext()));
111 builder.setAdvance(detail.advance);
112 builder.setMatch(key.getMatch());
114 if (LOG.isTraceEnabled()) {
115 LOG.trace("Attributes for classify session {} successfully read: {}", id, builder.build());
120 private OpaqueIndex readOpaqueIndex(final int tableIndex, final int opaqueIndex, final MappingContext ctx) {
121 // We first try to map the value to a vpp node, if that fails, simply wrap the u32 value
122 // TODO: HONEYCOMB-118 the approach might fail if the opaqueIndex contains small value that collides
123 // with some of the adjacent nodes
125 final Optional<VppNode> node = readVppNode(tableIndex, opaqueIndex, classifyTableContext, ctx, LOG);
126 if (node.isPresent()) {
127 return new OpaqueIndex(node.get());
129 return new OpaqueIndex(UnsignedInts.toLong(opaqueIndex));
134 private ClassifySessionDetailsReplyDump dumpClassifySessions(@Nonnull final InstanceIdentifier<?> id,
135 @Nonnull final ReadContext ctx)
136 throws ReadFailedException {
137 final ClassifyTableKey tableKey = id.firstKeyOf(ClassifyTable.class);
138 checkArgument(tableKey != null, "could not find ClassifyTable key in {}", id);
140 final String cacheKey = CACHE_KEY + tableKey;
142 ClassifySessionDetailsReplyDump classifySessionDump =
143 (ClassifySessionDetailsReplyDump) ctx.getModificationCache().get(cacheKey);
144 if (classifySessionDump != null) {
145 LOG.debug("Classify sessions is present in cache: {}", cacheKey);
146 return classifySessionDump;
149 final String tableName = tableKey.getName();
150 checkState(classifyTableContext.containsTable(tableName, ctx.getMappingContext()),
151 "Reading classify sessions for table {}, but table index could not be found in the classify table context",
153 final int tableId = classifyTableContext.getTableIndex(tableName, ctx.getMappingContext());
154 LOG.debug("Dumping classify sessions for classify table id={}", tableId);
157 final ClassifySessionDump dumpRequest = new ClassifySessionDump();
158 dumpRequest.tableId = tableId;
159 classifySessionDump = TranslateUtils
160 .getReplyForRead(getFutureJVpp().classifySessionDump(dumpRequest).toCompletableFuture(), id);
162 if (classifySessionDump != null) {
164 ctx.getModificationCache().put(cacheKey, classifySessionDump);
167 return classifySessionDump;
168 } catch (VppBaseCallException e) {
169 throw new ReadFailedException(id, e);
173 private static Optional<ClassifySessionDetails> findClassifySessionDetailsByMatch(
174 @Nullable final ClassifySessionDetailsReplyDump classifySessionDump, @Nonnull final byte[] match) {
175 if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
176 final List<ClassifySessionDetails> details = classifySessionDump.classifySessionDetails;
177 final List<ClassifySessionDetails> filteredSessions = details.stream()
178 .filter(singleDetail -> Arrays.equals(singleDetail.match, match)).collect(Collectors.toList());
179 if (filteredSessions.isEmpty()) {
180 return Optional.absent();
181 } else if (filteredSessions.size() == 1) {
182 return Optional.of(filteredSessions.get(0));
184 throw new IllegalStateException(String.format(
185 "Found %d classify sessions witch given match. Single session expected.",
186 filteredSessions.size()));
189 return Optional.absent();
194 public List<ClassifySessionKey> getAllIds(@Nonnull final InstanceIdentifier<ClassifySession> id,
195 @Nonnull final ReadContext ctx) throws ReadFailedException {
196 LOG.debug("Reading list of keys for classify sessions: {}", id);
198 final ClassifySessionDetailsReplyDump classifySessionDump = dumpClassifySessions(id, ctx);
199 if (classifySessionDump != null && classifySessionDump.classifySessionDetails != null) {
200 return classifySessionDump.classifySessionDetails.stream()
201 .map(detail -> new ClassifySessionKey(new HexString(printHexBinary(detail.match))))
202 .collect(Collectors.toList());
204 return Collections.emptyList();