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.v3po.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.v3po.translate.v3po.util.TranslateUtils.booleanToByte;
24 import com.google.common.base.Optional;
25 import io.fd.honeycomb.v3po.translate.MappingContext;
26 import io.fd.honeycomb.v3po.translate.spi.write.ListWriterCustomizer;
27 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
28 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
29 import io.fd.honeycomb.v3po.translate.v3po.util.TranslateUtils;
30 import io.fd.honeycomb.v3po.translate.v3po.util.WriteTimeoutException;
31 import io.fd.honeycomb.v3po.translate.write.WriteContext;
32 import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
33 import java.util.List;
34 import java.util.concurrent.CompletionStage;
35 import javax.annotation.Nonnull;
36 import javax.xml.bind.DatatypeConverter;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.VppClassifier;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTable;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.rev150603.vpp.classifier.ClassifyTableKey;
40 import org.opendaylight.yangtools.yang.binding.DataObject;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.openvpp.jvpp.VppBaseCallException;
43 import org.openvpp.jvpp.dto.ClassifyAddDelTable;
44 import org.openvpp.jvpp.dto.ClassifyAddDelTableReply;
45 import org.openvpp.jvpp.future.FutureJVpp;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * Writer customizer responsible for classify table create/delete. <br> Sends {@code classify_add_del_table} message to
51 * VPP.<br> Equivalent to invoking {@code vppctl classify table} command.
53 public class ClassifyTableWriter extends FutureJVppCustomizer
54 implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey> {
56 private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
57 private final NamingContext classifyTableContext;
59 public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp,
60 @Nonnull final NamingContext classifyTableContext) {
62 this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
67 public Optional<List<ClassifyTable>> extract(@Nonnull final InstanceIdentifier<ClassifyTable> currentId,
68 @Nonnull final DataObject parentData) {
69 return Optional.fromNullable(((VppClassifier) parentData).getClassifyTable());
73 public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
74 @Nonnull final ClassifyTable dataAfter, @Nonnull final WriteContext writeContext)
75 throws WriteFailedException {
76 LOG.debug("Creating classify table: iid={} dataAfter={}", id, dataAfter);
78 final int newTableIndex =
79 classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext());
81 // Add classify table name <-> vpp index mapping to the naming context:
82 classifyTableContext.addName(newTableIndex, dataAfter.getName(), writeContext.getMappingContext());
83 LOG.debug("Successfully created classify table(id={]): iid={} dataAfter={}", newTableIndex, id, dataAfter);
84 } catch (VppBaseCallException e) {
85 throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
90 public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
91 @Nonnull final ClassifyTable dataBefore, @Nonnull final ClassifyTable dataAfter,
92 @Nonnull final WriteContext writeContext) throws WriteFailedException {
93 LOG.warn("ClassifyTable update is not supported, ignoring configuration {}", dataAfter);
94 // TODO if only leaves were updated (but not child/aug nodes), we should throw exception to deny config change
98 public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<ClassifyTable> id,
99 @Nonnull final ClassifyTable dataBefore,
100 @Nonnull final WriteContext writeContext) throws WriteFailedException {
101 LOG.debug("Removing classify table: iid={} dataBefore={}", id, dataBefore);
102 final String tableName = dataBefore.getName();
103 checkState(classifyTableContext.containsIndex(tableName, writeContext.getMappingContext()),
104 "Removing classify table {}, but index could not be found in the classify table context", tableName);
106 final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
108 classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
110 // Remove deleted interface from interface context:
111 classifyTableContext.removeName(dataBefore.getName(), writeContext.getMappingContext());
112 LOG.debug("Successfully removed classify table(id={]): iid={} dataAfter={}", tableIndex, id, dataBefore);
113 } catch (VppBaseCallException e) {
114 throw new WriteFailedException.DeleteFailedException(id, e);
118 private int classifyAddDelTable(final boolean isAdd, @Nonnull final InstanceIdentifier<ClassifyTable> id,
119 @Nonnull final ClassifyTable table, final int tableId, final MappingContext ctx)
120 throws VppBaseCallException, WriteTimeoutException {
121 final CompletionStage<ClassifyAddDelTableReply> createClassifyTableReplyCompletionStage =
122 getFutureJVpp().classifyAddDelTable(getClassifyAddDelTableRequest(isAdd, tableId, table, ctx));
124 final ClassifyAddDelTableReply reply =
125 TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
126 return reply.newTableIndex;
130 private ClassifyAddDelTable getClassifyAddDelTableRequest(final boolean isAdd, final int tableIndex,
131 @Nonnull final ClassifyTable table,
132 @Nonnull final MappingContext ctx) {
133 final ClassifyAddDelTable request = new ClassifyAddDelTable();
134 request.isAdd = booleanToByte(isAdd);
135 request.tableIndex = tableIndex;
137 // mandatory, all u32 values are permitted:
138 request.nbuckets = table.getNbuckets().intValue();
139 request.memorySize = table.getMemorySize().intValue();
140 request.skipNVectors = table.getSkipNVectors().intValue();
143 // TODO implement node name to index conversion after https://jira.fd.io/browse/VPP-203 is fixed
144 request.missNextIndex = table.getMissNextIndex().getPacketHandlingAction().getIntValue();
146 final String nextTable = table.getNextTable();
147 if (nextTable != null) {
148 request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx);
150 request.nextTableIndex = ~0; // value not specified
152 request.mask = DatatypeConverter.parseHexBinary(table.getMask().getValue().replace(":", ""));
153 checkArgument(request.mask.length % 16 == 0, "Number of mask bytes must be multiple of 16.");
154 request.matchNVectors = request.mask.length / 16;