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;
21 import com.google.common.base.Optional;
22 import com.google.common.base.Preconditions;
23 import io.fd.honeycomb.translate.v3po.interfaces.acl.IetfAclWriter;
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.WriteContext;
27 import io.fd.honeycomb.translate.write.WriteFailedException;
28 import java.util.HashMap;
29 import java.util.List;
31 import java.util.concurrent.CompletionStage;
32 import java.util.stream.Collectors;
33 import java.util.stream.Stream;
34 import javax.annotation.Nonnegative;
35 import javax.annotation.Nonnull;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries;
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.matches.AceType;
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.matches.ace.type.AceEth;
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.ace.type.AceIp;
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.ace.type.ace.ip.AceIpVersion;
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.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.ietf.acl.base.attributes.access.lists.Acl;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import io.fd.vpp.jvpp.VppBaseCallException;
48 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
49 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply;
50 import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface;
51 import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply;
52 import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
53 import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply;
54 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 public final class IetfAClWriter implements JvppReplyConsumer {
60 private static final Logger LOG = LoggerFactory.getLogger(IetfAClWriter.class);
61 private final FutureJVppCore jvpp;
63 private Map<AclType, AceWriter> aceWriters = new HashMap<>();
65 public IetfAClWriter(@Nonnull final FutureJVppCore futureJVppCore) {
66 this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null");
67 aceWriters.put(AclType.ETH, new AceEthWriter(futureJVppCore));
68 aceWriters.put(AclType.IP4, new AceIp4Writer(futureJVppCore));
69 aceWriters.put(AclType.IP6, new AceIp6Writer(futureJVppCore));
72 private static Stream<Ace> aclToAceStream(@Nonnull final Acl assignedAcl,
73 @Nonnull final WriteContext writeContext) {
74 final String aclName = assignedAcl.getName();
75 final Class<? extends AclBase> aclType = assignedAcl.getType();
77 // ietf-acl updates are handled first, so we use writeContext.readAfter
78 final Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl>
79 aclOptional = writeContext.readAfter(IetfAclWriter.ACL_ID.child(
80 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class,
81 new AclKey(aclName, aclType)));
82 checkArgument(aclOptional.isPresent(), "Acl lists not configured");
83 final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl
84 acl = aclOptional.get();
86 final AccessListEntries accessListEntries = acl.getAccessListEntries();
87 checkArgument(accessListEntries != null, "access list entries not configured");
89 return accessListEntries.getAce().stream();
92 void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex)
93 throws WriteTimeoutException, WriteFailedException.DeleteFailedException {
94 final ClassifyTableByInterface request = new ClassifyTableByInterface();
95 request.swIfIndex = swIfIndex;
98 final CompletionStage<ClassifyTableByInterfaceReply> cs = jvpp.classifyTableByInterface(request);
99 final ClassifyTableByInterfaceReply reply = getReplyForWrite(cs.toCompletableFuture(), id);
101 // We unassign and remove all ACL-related classify tables for given interface (we assume we are the only
102 // classify table manager)
104 unassignClassifyTables(id, reply);
106 removeClassifyTable(id, reply.l2TableId);
107 removeClassifyTable(id, reply.ip4TableId);
108 removeClassifyTable(id, reply.ip6TableId);
109 } catch (VppBaseCallException e) {
110 throw new WriteFailedException.DeleteFailedException(id, e);
114 private void unassignClassifyTables(@Nonnull final InstanceIdentifier<?> id,
115 final ClassifyTableByInterfaceReply currentState)
116 throws VppBaseCallException, WriteTimeoutException {
117 final InputAclSetInterface request = new InputAclSetInterface();
119 request.swIfIndex = currentState.swIfIndex;
120 request.l2TableIndex = currentState.l2TableId;
121 request.ip4TableIndex = currentState.ip4TableId;
122 request.ip6TableIndex = currentState.ip6TableId;
123 final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
124 jvpp.inputAclSetInterface(request);
125 getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
128 private void removeClassifyTable(@Nonnull final InstanceIdentifier<?> id, final int tableIndex)
129 throws VppBaseCallException, WriteTimeoutException {
131 if (tableIndex == -1) {
132 return; // classify table id is absent
134 final ClassifyAddDelTable request = new ClassifyAddDelTable();
135 request.tableIndex = tableIndex;
136 final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request);
137 getReplyForWrite(cs.toCompletableFuture(), id);
140 void write(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex, @Nonnull final List<Acl> acls,
141 @Nonnull final WriteContext writeContext)
142 throws VppBaseCallException, WriteTimeoutException {
143 write(id, swIfIndex, acls, writeContext, 0);
146 void write(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex, @Nonnull final List<Acl> acls,
147 @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags)
148 throws VppBaseCallException, WriteTimeoutException {
150 // filter ACE entries and group by AceType
151 final Map<AclType, List<Ace>> acesByType = acls.stream()
152 .flatMap(acl -> aclToAceStream(acl, writeContext))
153 .collect(Collectors.groupingBy(AclType::fromAce));
155 final InputAclSetInterface request = new InputAclSetInterface();
157 request.swIfIndex = swIfIndex;
158 request.l2TableIndex = -1;
159 request.ip4TableIndex = -1;
160 request.ip6TableIndex = -1;
163 for (Map.Entry<AclType, List<Ace>> entry : acesByType.entrySet()) {
164 final AclType aceType = entry.getKey();
165 final List<Ace> aces = entry.getValue();
166 LOG.trace("Processing ACEs of {} type: {}", aceType, aces);
168 final AceWriter aceWriter = aceWriters.get(aceType);
169 if (aceWriter == null) {
170 LOG.warn("AceProcessor for {} not registered. Skipping ACE.", aceType);
172 aceWriter.write(id, aces, request, numberOfTags);
176 final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
177 jvpp.inputAclSetInterface(request);
178 getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
181 private enum AclType {
185 private static AclType fromAce(final Ace ace) {
186 AclType result = null;
187 final AceType aceType;
189 aceType = ace.getMatches().getAceType();
190 if (aceType instanceof AceEth) {
192 } else if (aceType instanceof AceIp) {
193 final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion();
194 if (aceIpVersion instanceof AceIpv4) {
200 } catch (NullPointerException e) {
201 throw new IllegalArgumentException("Incomplete ACE: " + ace, e);
203 if (result == null) {
204 throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType));