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