4f59ffe8e2a7a109b850b3b5d8277031e73a3f13
[hc2vpp.git] /
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package io.fd.honeycomb.v3po.translate.v3po.vppclassifier;
18
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;
23
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;
48
49 /**
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.
52  */
53 public class ClassifyTableWriter extends FutureJVppCustomizer
54     implements ListWriterCustomizer<ClassifyTable, ClassifyTableKey> {
55
56     private static final Logger LOG = LoggerFactory.getLogger(ClassifyTableWriter.class);
57     private final NamingContext classifyTableContext;
58
59     public ClassifyTableWriter(@Nonnull final FutureJVpp futureJvpp,
60                                @Nonnull final NamingContext classifyTableContext) {
61         super(futureJvpp);
62         this.classifyTableContext = checkNotNull(classifyTableContext, "classifyTableContext should not be null");
63     }
64
65     @Nonnull
66     @Override
67     public Optional<List<ClassifyTable>> extract(@Nonnull final InstanceIdentifier<ClassifyTable> currentId,
68                                                  @Nonnull final DataObject parentData) {
69         return Optional.fromNullable(((VppClassifier) parentData).getClassifyTable());
70     }
71
72     @Override
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);
77         try {
78             final int newTableIndex =
79                 classifyAddDelTable(true, id, dataAfter, ~0 /* value not present */, writeContext.getMappingContext());
80
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);
86         }
87     }
88
89     @Override
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
95     }
96
97     @Override
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);
105
106         final int tableIndex = classifyTableContext.getIndex(tableName, writeContext.getMappingContext());
107         try {
108             classifyAddDelTable(false, id, dataBefore, tableIndex, writeContext.getMappingContext());
109
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);
115         }
116     }
117
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));
123
124         final ClassifyAddDelTableReply reply =
125             TranslateUtils.getReplyForWrite(createClassifyTableReplyCompletionStage.toCompletableFuture(), id);
126         return reply.newTableIndex;
127
128     }
129
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;
136
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();
141
142         // mandatory
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();
145
146         final String nextTable = table.getNextTable();
147         if (nextTable != null) {
148             request.nextTableIndex = classifyTableContext.getIndex(nextTable, ctx);
149         } else {
150             request.nextTableIndex = ~0; // value not specified
151         }
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;
155
156         return request;
157     }
158 }