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.interfaces.acl.ingress;
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
22 import com.google.common.annotations.VisibleForTesting;
23 import io.fd.honeycomb.translate.util.RWUtils;
24 import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
25 import io.fd.honeycomb.translate.vpp.util.WriteTimeoutException;
26 import io.fd.honeycomb.translate.write.WriteFailedException;
27 import io.fd.vpp.jvpp.VppBaseCallException;
28 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
29 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
30 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
31 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
32 import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
33 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
34 import java.util.List;
35 import java.util.concurrent.CompletionStage;
36 import java.util.stream.Collector;
37 import javax.annotation.Nonnegative;
38 import javax.annotation.Nonnull;
39 import javax.annotation.Nullable;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.AceType;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceMode;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 * Base writer for translation of ietf-acl model ACEs to VPP's classify tables and sessions. <p/> Creates one classify
49 * table with single session per ACE.
51 * @param <T> type of access control list entry
53 abstract class AbstractAceWriter<T extends AceType> implements AceWriter, JvppReplyConsumer {
55 // TODO: HONEYCOMB-181 minimise memory used by classify tables (we create a lot of them to make ietf-acl model
56 // mapping more convenient):
57 // according to https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers#Creating_a_classifier_table,
58 // classify table needs 16*(1 + match_n_vectors) bytes, but this does not quite work, so setting 8K for now
59 protected static final int TABLE_MEM_SIZE = 8 * 1024;
62 static final int VLAN_TAG_LEN = 4;
64 private static final Collector<PacketHandling, ?, PacketHandling> SINGLE_ITEM_COLLECTOR =
65 RWUtils.singleItemCollector();
67 private final FutureJVppCore futureJVppCore;
69 public AbstractAceWriter(@Nonnull final FutureJVppCore futureJVppCore) {
70 this.futureJVppCore = checkNotNull(futureJVppCore, "futureJVppCore should not be null");
74 * Creates classify table for given ACE.
76 * @param action packet handling action (permit/deny)
77 * @param ace ACE to be translated
78 * @param mode interface mode
79 * @param nextTableIndex classify table index
80 * @param vlanTags number of vlan tags
81 * @return classify table that represents given ACE
83 protected abstract ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
85 @Nullable final InterfaceMode mode,
86 final int nextTableIndex,
90 * Creates classify session for given ACE.
92 * @param action packet handling action (permit/deny)
93 * @param ace ACE to be translated
94 * @param mode interface mode
95 * @param tableIndex classify table index for the given session
96 * @param vlanTags number of vlan tags
97 * @return classify session that represents given ACE
99 protected abstract ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
100 @Nonnull final T ace,
101 @Nullable final InterfaceMode mode,
102 final int tableIndex,
106 * Sets classify table index for input_acl_set_interface request.
108 * @param request request DTO
109 * @param tableIndex pointer to a chain of classify tables
111 protected abstract void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex);
114 public final void write(@Nonnull final InstanceIdentifier<?> id, @Nonnull final List<Ace> aces,
115 final InterfaceMode mode, @Nonnull final InputAclSetInterface request,
116 @Nonnegative final int vlanTags)
117 throws WriteFailedException {
118 final PacketHandling action = aces.stream().map(ace -> ace.getActions().getPacketHandling()).distinct()
119 .collect(SINGLE_ITEM_COLLECTOR);
121 checkArgument(vlanTags >= 0 && vlanTags <= 2, "Number of vlan tags %s is not in [0,2] range");
122 int nextTableIndex = -1;
123 for (final Ace ace : aces) {
124 // Create table + session per entry
126 final ClassifyAddDelTable ctRequest =
127 createClassifyTable(action, (T) ace.getMatches().getAceType(), mode, nextTableIndex, vlanTags);
128 nextTableIndex = createClassifyTable(id, ctRequest);
129 createClassifySession(id,
130 createClassifySession(action, (T) ace.getMatches().getAceType(), mode, nextTableIndex, vlanTags));
132 setClassifyTable(request, nextTableIndex);
135 private int createClassifyTable(@Nonnull final InstanceIdentifier<?> id,
136 @Nonnull final ClassifyAddDelTable request)
137 throws WriteFailedException {
138 final CompletionStage<ClassifyAddDelTableReply> cs = futureJVppCore.classifyAddDelTable(request);
140 final ClassifyAddDelTableReply reply = getReplyForWrite(cs.toCompletableFuture(), id);
141 return reply.newTableIndex;
144 private void createClassifySession(@Nonnull final InstanceIdentifier<?> id,
145 @Nonnull final ClassifyAddDelSession request)
146 throws WriteFailedException {
147 final CompletionStage<ClassifyAddDelSessionReply> cs = futureJVppCore.classifyAddDelSession(request);
149 getReplyForWrite(cs.toCompletableFuture(), id);
152 protected ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action, final int nextTableIndex) {
153 final ClassifyAddDelTable request = new ClassifyAddDelTable();
155 request.tableIndex = -1; // value not present
157 request.nbuckets = 1; // we expect exactly one session per table
159 if (action instanceof Permit) {
160 request.missNextIndex = 0; // for list of permit rules, deny (0) should be default action
161 } else { // deny is default value
162 request.missNextIndex = -1; // for list of deny rules, permit (-1) should be default action
165 request.nextTableIndex = nextTableIndex;
166 request.memorySize = TABLE_MEM_SIZE;
171 protected ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action, final int tableIndex) {
172 final ClassifyAddDelSession request = new ClassifyAddDelSession();
174 request.tableIndex = tableIndex;
175 request.opaqueIndex = ~0; // value not used
177 if (action instanceof Permit) {
178 request.hitNextIndex = -1;
179 } // deny (0) is default value
184 protected int getVlanTagsLen(final int vlanTags) {
185 return vlanTags * VLAN_TAG_LEN;