diff options
author | Marek Gradzki <mgradzki@cisco.com> | 2016-08-24 16:52:03 +0200 |
---|---|---|
committer | Marek Gradzki <mgradzki@cisco.com> | 2016-08-26 12:39:27 +0200 |
commit | b257036c963d274e2bcee43adc309782e5ddeab5 (patch) | |
tree | 20286c6a0600439b21c85fde021d5fd3ae118d74 /v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java | |
parent | cefd2555dbf421a62269c393d0d9d28964f38e2b (diff) |
HONEYCOMB-139: ietf-acl translation layer. L2 ACL support
Change-Id: I2b7de991e8d49c20fce66a5f4b193d0060feae56
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java')
-rw-r--r-- | v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java new file mode 100644 index 000000000..5eb4af5e1 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.v3po.acl.AclWriter; +import io.fd.honeycomb.translate.v3po.util.TranslateUtils; +import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace; +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; +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; +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; +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; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.ietf.acl.base.attributes.access.lists.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.openvpp.jvpp.VppBaseCallException; +import org.openvpp.jvpp.core.dto.ClassifyAddDelTable; +import org.openvpp.jvpp.core.dto.ClassifyAddDelTableReply; +import org.openvpp.jvpp.core.dto.ClassifyTableByInterface; +import org.openvpp.jvpp.core.dto.ClassifyTableByInterfaceReply; +import org.openvpp.jvpp.core.dto.InputAclSetInterface; +import org.openvpp.jvpp.core.dto.InputAclSetInterfaceReply; +import org.openvpp.jvpp.core.future.FutureJVppCore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class IetfAClWriter { + + private static final Logger LOG = LoggerFactory.getLogger(IetfAClWriter.class); + private final FutureJVppCore jvpp; + + private Map<AclType, AceWriter> aceWriters = new HashMap<>(); + + public IetfAClWriter(@Nonnull final FutureJVppCore futureJVppCore) { + this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null"); + aceWriters.put(AclType.ETH, new AceEthWriter(futureJVppCore)); + } + + void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex) + throws WriteTimeoutException, WriteFailedException.DeleteFailedException { + final ClassifyTableByInterface request = new ClassifyTableByInterface(); + request.swIfIndex = swIfIndex; + jvpp.classifyTableByInterface(request); + + try { + final CompletionStage<ClassifyTableByInterfaceReply> cs = jvpp.classifyTableByInterface(request); + final ClassifyTableByInterfaceReply reply = TranslateUtils.getReplyForWrite(cs.toCompletableFuture(), id); + + // We remove all ACL-related classify tables for given interface (we assume we are the only classify table + // manager) + removeClassifyTable(id, reply.l2TableId); + removeClassifyTable(id, reply.ip4TableId); + removeClassifyTable(id, reply.ip6TableId); + } catch (VppBaseCallException e) { + throw new WriteFailedException.DeleteFailedException(id, e); + } + } + + private void removeClassifyTable(@Nonnull final InstanceIdentifier<?> id, final int tableIndex) + throws VppBaseCallException, WriteTimeoutException { + + if (tableIndex == -1) { + return; // classify table id is absent + } + final ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.tableIndex = tableIndex; + final CompletionStage<ClassifyAddDelTableReply> cs = jvpp.classifyAddDelTable(request); + TranslateUtils.getReplyForWrite(cs.toCompletableFuture(), id); + } + + void write(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex, @Nonnull final List<Acl> acls, + @Nonnull final WriteContext writeContext) + throws VppBaseCallException, WriteTimeoutException { + + // filter ACE entries and group by AceType + final Map<AclType, List<Ace>> acesByType = acls.stream() + .flatMap(acl -> aclToAceStream(acl, writeContext)) + // TODO we should not tolerate nulls, but throw some meaningful exceptions instead + .filter(ace -> ace != null && ace.getMatches() != null && ace.getMatches().getAceType() != null && + ace.getActions() != null && ace.getActions().getPacketHandling() != null) + .collect(Collectors.groupingBy(AclType::fromAce)); + + final InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = 1; + request.swIfIndex = swIfIndex; + request.l2TableIndex = -1; + request.ip4TableIndex = -1; + request.ip6TableIndex = -1; + + // for each AceType: + for (Map.Entry<AclType, List<Ace>> entry : acesByType.entrySet()) { + final AclType aceType = entry.getKey(); + final List<Ace> aces = entry.getValue(); + LOG.trace("Processing ACEs of {} type: {}", aceType, aces); + + final AceWriter aceWriter = aceWriters.get(aceType); + if (aceWriter == null) { + LOG.warn("AceProcessor for {} not registered. Skipping ACE.", aceType); + } else { + aceWriter.write(id, aces, request); + } + } + + final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage = + jvpp.inputAclSetInterface(request); + TranslateUtils.getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); + + } + + private static Stream<Ace> aclToAceStream(@Nonnull final Acl assignedAcl, + @Nonnull final WriteContext writeContext) { + final String aclName = assignedAcl.getName(); + final Class<? extends AclBase> aclType = assignedAcl.getType(); + + // ietf-acl updates are handled first, so we use writeContext.readAfter + final Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl> + aclOptional = writeContext.readAfter(AclWriter.ACL_ID.child( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class, + new AclKey(aclName, aclType))); + checkArgument(aclOptional.isPresent(), "Acl lists not configured"); + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl + acl = aclOptional.get(); + + final AccessListEntries accessListEntries = acl.getAccessListEntries(); + checkArgument(accessListEntries != null, "access list entries not configured"); + + return accessListEntries.getAce().stream(); + } + + private enum AclType { + ETH, IP4, IP6; + + @Nonnull + private static AclType fromAce(final Ace ace) { + AclType result = null; + final AceType aceType = ace.getMatches().getAceType(); + if (aceType instanceof AceEth) { + result = ETH; + } else if (aceType instanceof AceIp) { + final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion(); + if (aceIpVersion instanceof AceIpv4) { + result = IP4; + } else { + result = IP6; + } + } + if (result == null) { + throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType)); + } + return result; + } + } +} |