2 * Copyright (c) 2017 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.hc2vpp.vpp.classifier.write.acl.common;
19 import static com.google.common.base.Preconditions.checkArgument;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
24 import io.fd.honeycomb.translate.write.WriteContext;
25 import io.fd.honeycomb.translate.write.WriteFailedException;
26 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
27 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply;
28 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
29 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
30 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.ListIterator;
35 import java.util.concurrent.CompletionStage;
36 import java.util.function.Predicate;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import javax.annotation.Nonnull;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries;
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;
44 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;
45 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;
46 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.ace.type.AceEth;
47 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.ace.type.AceIp;
48 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.ace.type.ace.ip.AceIpVersion;
49 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.ace.type.ace.ip.ace.ip.version.AceIpv4;
50 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.ace.type.ace.ip.ace.ip.version.AceIpv6;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.context.rev161214.mapping.entry.context.attributes.acl.mapping.entry.context.mapping.table.MappingEntry;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.InterfaceMode;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpAndEth;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.AccessLists;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
56 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
60 public abstract class AbstractIetfAclWriter implements IetfAclWriter, JvppReplyConsumer, AclTranslator {
62 private static final Logger LOG = LoggerFactory.getLogger(AbstractIetfAclWriter.class);
63 protected static final int NOT_DEFINED = -1;
64 protected final FutureJVppCore jvpp;
66 private Map<AclType, AceWriter<? extends AceType>> aceWriters = new HashMap<>();
68 public AbstractIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) {
69 this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null");
70 aceWriters.put(AclType.ETH, new AceEthWriter());
71 aceWriters.put(AclType.IP4, new AceIp4Writer());
72 aceWriters.put(AclType.IP6, new AceIp6Writer());
73 aceWriters.put(AclType.ETH_AND_IP, new AceIpAndEthWriter());
76 private static Stream<Ace> aclToAceStream(@Nonnull final Acl assignedAcl,
77 @Nonnull final WriteContext writeContext) {
78 final String aclName = assignedAcl.getName();
79 final Class<? extends AclBase> aclType = assignedAcl.getType();
81 // ietf-acl updates are handled first, so we use writeContext.readAfter
82 final Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl>
84 writeContext.readAfter(io.fd.hc2vpp.vpp.classifier.write.acl.IetfAclWriter.ACL_ID.child(
85 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class,
86 new AclKey(aclName, aclType)));
87 checkArgument(aclOptional.isPresent(), "Acl lists not configured");
88 final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl
89 acl = aclOptional.get();
91 final AccessListEntries accessListEntries = acl.getAccessListEntries();
92 checkArgument(accessListEntries != null, "access list entries not configured");
94 return accessListEntries.getAce().stream();
97 protected void removeClassifyTables(@Nonnull final InstanceIdentifier<?> id, @Nonnull final MappingEntry entry)
98 throws WriteFailedException {
99 removeClassifyTable(id, entry.getL2TableId());
100 removeClassifyTable(id, entry.getIp4TableId());
101 removeClassifyTable(id, entry.getIp6TableId());
104 private void removeClassifyTable(@Nonnull final InstanceIdentifier<?> id, final int tableIndex)
105 throws WriteFailedException {
107 if (tableIndex == -1) {
108 return; // classify table id is absent
110 final ClassifyAddDelTable request = new ClassifyAddDelTable();
111 request.delChain = 1;
112 request.tableIndex = tableIndex;
113 final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
114 getReplyForDelete(cs.toCompletableFuture(), id);
117 protected static boolean appliesToIp4Path(final Ace ace) {
118 final AceType aceType = ace.getMatches().getAceType();
119 final AclType aclType = AclType.fromAce(ace);
120 if (aclType == AclType.IP4) {
123 if (aclType == AclType.ETH) {
124 return true; // L2 only rules are possible for IP4 traffic
126 if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType).getAceIpAndEthNodes()
127 .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.ace.ip.version.AceIpv4) {
133 protected static boolean appliesToIp6Path(final Ace ace) {
134 final AceType aceType = ace.getMatches().getAceType();
135 final AclType aclType = AclType.fromAce(ace);
136 if (aclType == AclType.IP6) {
139 if (aclType == AclType.ETH) {
140 return true; // L2 only rules are possible for IP6 traffic
142 if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType).getAceIpAndEthNodes()
143 .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.classifier.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.and.eth.nodes.ace.ip.version.AceIpv6) {
149 protected static List<Ace> getACEs(@Nonnull final List<Acl> acls, @Nonnull final WriteContext writeContext,
150 final Predicate<? super Ace> filter) {
151 return acls.stream().flatMap(acl -> aclToAceStream(acl, writeContext)).filter(filter)
152 .collect(Collectors.toList());
155 protected int writeAces(final InstanceIdentifier<?> id, final List<Ace> aces,
156 final AccessLists.DefaultAction defaultAction, final InterfaceMode mode,
157 final int vlanTags) throws WriteFailedException {
158 if (aces.isEmpty()) {
162 int nextTableIndex = configureDefaultAction(id, defaultAction);
163 final ListIterator<Ace> iterator = aces.listIterator(aces.size());
164 while (iterator.hasPrevious()) {
165 final Ace ace = iterator.previous();
166 LOG.trace("Processing ACE: {}", ace);
168 final AceWriter aceWriter =
169 aceWriters.get(AclType.fromAce(ace));
170 if (aceWriter == null) {
171 LOG.warn("AceProcessor for {} not registered. Skipping ACE.", ace.getClass());
173 final AceType aceType = ace.getMatches().getAceType();
174 final PacketHandling action = ace.getActions().getPacketHandling();
175 final ClassifyAddDelTable ctRequest = aceWriter.createTable(aceType, mode, nextTableIndex, vlanTags);
176 nextTableIndex = createClassifyTable(id, ctRequest);
177 final List<ClassifyAddDelSession> sessionRequests =
178 aceWriter.createSession(action, aceType, mode, nextTableIndex, vlanTags);
179 for (ClassifyAddDelSession csRequest : sessionRequests) {
180 createClassifySession(id, csRequest);
184 return nextTableIndex;
187 private int configureDefaultAction(@Nonnull final InstanceIdentifier<?> id,
188 final AccessLists.DefaultAction defaultAction)
189 throws WriteFailedException {
190 ClassifyAddDelTable ctRequest = createTable(-1);
191 if (AccessLists.DefaultAction.Permit.equals(defaultAction)) {
192 ctRequest.missNextIndex = -1;
194 ctRequest.missNextIndex = 0;
196 ctRequest.mask = new byte[16];
197 ctRequest.skipNVectors = 0;
198 ctRequest.matchNVectors = 1;
199 return createClassifyTable(id, ctRequest);
202 private int createClassifyTable(@Nonnull final InstanceIdentifier<?> id,
203 @Nonnull final ClassifyAddDelTable request)
204 throws WriteFailedException {
205 final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
207 final ClassifyAddDelTableReply reply = getReplyForWrite(cs.toCompletableFuture(), id);
208 return reply.newTableIndex;
211 private void createClassifySession(@Nonnull final InstanceIdentifier<?> id,
212 @Nonnull final ClassifyAddDelSession request)
213 throws WriteFailedException {
214 final CompletionStage<ClassifyAddDelSessionReply> cs = jvpp.classifyAddDelSession(request);
216 getReplyForWrite(cs.toCompletableFuture(), id);
219 private enum AclType {
220 ETH, IP4, IP6, ETH_AND_IP;
223 private static AclType fromAce(final Ace ace) {
224 AclType result = null;
225 final AceType aceType;
227 aceType = ace.getMatches().getAceType();
228 if (aceType instanceof AceEth) {
230 } else if (aceType instanceof AceIp) {
231 final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion();
232 if (aceIpVersion == null) {
233 throw new IllegalArgumentException("Incomplete ACE (ip-version was not provided): " + ace);
235 if (aceIpVersion instanceof AceIpv4) {
237 } else if (aceIpVersion instanceof AceIpv6) {
240 } else if (aceType instanceof AceIpAndEth) {
243 } catch (NullPointerException e) {
244 throw new IllegalArgumentException("Incomplete ACE: " + ace, e);
246 if (result == null) {
247 throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType));