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