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