From f8273e10b19ecc82bdda81feef9982ce28d5de21 Mon Sep 17 00:00:00 2001 From: Jan Srnicek Date: Fri, 16 Dec 2016 13:07:56 +0100 Subject: HONEYCOMB-310: translation layer for acl plugin Not covered by this patch (moved to subsequent commits): - postman collection - distinguish ingress/egress ACLs while reading assigned acls - proper support for acl tag - unit tests improvements - read for acls (not necessarily assigned) - initializers Change-Id: I5a198ce1a6e20d0b1d95b4d2d83d0464fb86580c Signed-off-by: Jan Srnicek Signed-off-by: Marek Gradzki --- .../src/main/java/io/fd/hc2vpp/acl/AclModule.java | 82 +++++++++ .../java/io/fd/hc2vpp/acl/JVppAclProvider.java | 73 ++++++++ .../io/fd/hc2vpp/acl/read/VppAclCustomizer.java | 194 ++++++++++++++++++++ .../fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java | 143 +++++++++++++++ .../read/factory/InterfaceAclReaderFactory.java | 85 +++++++++ .../hc2vpp/acl/util/FutureJVppAclCustomizer.java | 38 ++++ .../io/fd/hc2vpp/acl/util/ace/AceConverter.java | 94 ++++++++++ .../util/ace/extractor/MacIpAceDataExtractor.java | 83 +++++++++ .../ace/extractor/StandardAceDataExtractor.java | 98 ++++++++++ .../fd/hc2vpp/acl/util/acl/AclDataExtractor.java | 68 +++++++ .../io/fd/hc2vpp/acl/util/acl/AclValidator.java | 84 +++++++++ .../java/io/fd/hc2vpp/acl/util/acl/AclWriter.java | 125 +++++++++++++ .../iface/acl/AclInterfaceAssignmentRequest.java | 162 ++++++++++++++++ .../macip/MacIpInterfaceAssignmentRequest.java | 111 +++++++++++ .../util/protocol/ProtoPreBindRuleProducer.java | 203 +++++++++++++++++++++ .../hc2vpp/acl/write/InterfaceAclCustomizer.java | 98 ++++++++++ .../acl/write/InterfaceAclMacIpCustomizer.java | 78 ++++++++ .../io/fd/hc2vpp/acl/write/VppAclCustomizer.java | 110 +++++++++++ .../write/factory/AbstractAclWriterFactory.java | 44 +++++ .../write/factory/InterfaceAclWriterFactory.java | 59 ++++++ .../acl/write/factory/VppAclWriterFactory.java | 82 +++++++++ 21 files changed, 2114 insertions(+) create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java create mode 100644 acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java (limited to 'acl/acl-impl/src/main/java') diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java new file mode 100644 index 000000000..f15119be6 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/AclModule.java @@ -0,0 +1,82 @@ +/* + * 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.hc2vpp.acl; + +import com.google.common.annotations.VisibleForTesting; +import com.google.inject.AbstractModule; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.name.Names; +import io.fd.hc2vpp.acl.read.factory.InterfaceAclReaderFactory; +import io.fd.hc2vpp.acl.write.factory.InterfaceAclWriterFactory; +import io.fd.hc2vpp.acl.write.factory.VppAclWriterFactory; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import net.jmob.guice.conf.core.ConfigurationModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AclModule extends AbstractModule { + + public static final String STANDARD_ACL_CONTEXT_NAME = "standard-acl-context"; + public static final String STANDARD_LEARNED_ACL_NAME_PREFIX = "standard-learned-acl-"; + public static final String MAC_IP_ACL_CONTEXT_NAME = "mac-ip-acl-context"; + public static final String MAC_IP_LEARNED_ACL_NAME_PREFIX = "mac-ip-acl-context"; + + private static final Logger LOG = LoggerFactory.getLogger(AclModule.class); + + private final Class> jvppAclProviderClass; + + public AclModule() { + this(JVppAclProvider.class); + } + + @VisibleForTesting + AclModule(@Nonnull final Class> jvppAclProviderClass) { + this.jvppAclProviderClass = jvppAclProviderClass; + } + + @Override + protected void configure() { + LOG.info("Configuring module Acl"); + install(ConfigurationModule.create()); + + // binds JVpp Acl future facade + bind(FutureJVppAclFacade.class).toProvider(jvppAclProviderClass).in(Singleton.class); + + bind(NamingContext.class).annotatedWith(Names.named(STANDARD_ACL_CONTEXT_NAME)) + .toInstance(new NamingContext(STANDARD_LEARNED_ACL_NAME_PREFIX, STANDARD_ACL_CONTEXT_NAME)); + + bind(NamingContext.class).annotatedWith(Names.named(MAC_IP_ACL_CONTEXT_NAME)) + .toInstance(new NamingContext(MAC_IP_LEARNED_ACL_NAME_PREFIX, MAC_IP_ACL_CONTEXT_NAME)); + + final Multibinder writerFactoryMultibinder = + Multibinder.newSetBinder(binder(), WriterFactory.class); + writerFactoryMultibinder.addBinding().to(VppAclWriterFactory.class); + writerFactoryMultibinder.addBinding().to(InterfaceAclWriterFactory.class); + + final Multibinder readerFactoryMultibinder = + Multibinder.newSetBinder(binder(), ReaderFactory.class); + readerFactoryMultibinder.addBinding().to(InterfaceAclReaderFactory.class); + + LOG.info("Module Acl successfully configured"); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java new file mode 100644 index 000000000..b3caa0e9c --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/JVppAclProvider.java @@ -0,0 +1,73 @@ +/* + * 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.hc2vpp.acl; + +import com.google.inject.Inject; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.honeycomb.infra.distro.ProviderTrait; +import io.fd.vpp.jvpp.JVppRegistry; +import io.fd.vpp.jvpp.VppBaseCallException; +import io.fd.vpp.jvpp.acl.JVppAclImpl; +import io.fd.vpp.jvpp.acl.dto.AclPluginGetVersion; +import io.fd.vpp.jvpp.acl.dto.AclPluginGetVersionReply; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.io.IOException; +import java.util.concurrent.TimeoutException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +class JVppAclProvider extends ProviderTrait implements JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(JVppAclProvider.class); + + @Inject + private JVppRegistry registry; + + private static JVppAclImpl initAclApi() { + final JVppAclImpl jvppAcl = new JVppAclImpl(); + // Free jvpp-acl plugin's resources on shutdown + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + LOG.info("Unloading jvpp-acl plugin"); + jvppAcl.close(); + LOG.info("Successfully unloaded jvpp-acl plugin"); + } + }); + return jvppAcl; + } + + @Override + protected FutureJVppAclFacade create() { + try { + return reportVersionAndGet(initAclApi()); + } catch (IOException e) { + throw new IllegalStateException("Unable to open VPP management connection", e); + } catch (TimeoutException | VppBaseCallException e) { + throw new IllegalStateException("Unable to load ACL plugin version", e); + } + } + + private FutureJVppAclFacade reportVersionAndGet(final JVppAclImpl jvppAcl) + throws IOException, TimeoutException, VppBaseCallException { + final FutureJVppAclFacade futureFacade = new FutureJVppAclFacade(registry, jvppAcl); + final AclPluginGetVersionReply pluginVersion = + getReply(futureFacade.aclPluginGetVersion(new AclPluginGetVersion()).toCompletableFuture()); + LOG.info("Acl plugin successfully loaded[version {}.{}]", pluginVersion.major, pluginVersion.minor); + return futureFacade; + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java new file mode 100644 index 000000000..90f2b2fe2 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppAclCustomizer.java @@ -0,0 +1,194 @@ +/* + * 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.hc2vpp.acl.read; + + +import com.google.common.base.Optional; +import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ListReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager.DumpCacheManagerBuilder; +import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor; +import io.fd.honeycomb.translate.util.read.cache.EntityDumpPostProcessingFunction; +import io.fd.vpp.jvpp.acl.dto.AclDetailsReplyDump; +import io.fd.vpp.jvpp.acl.dto.AclDump; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDetailsReplyDump; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceListDump; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.EgressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.IngressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAclsBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAclsKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppAcl; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VppAclCustomizer extends FutureJVppAclCustomizer + implements ListReaderCustomizer, JvppReplyConsumer, ByteDataTranslator { + + private final NamingContext interfaceContext; + private final NamingContext standardAclContext; + /** + * true == ingress + * false == egress + */ + private final boolean input; + private final DumpCacheManager aclReferenceDumpManager; + private final DumpCacheManager aclDumpManager; + + public VppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext standardAclContext, + final boolean input) { + super(jVppAclFacade); + this.interfaceContext = interfaceContext; + this.standardAclContext = standardAclContext; + this.input = input; + + aclReferenceDumpManager = + new DumpCacheManagerBuilder() + .withExecutor(createAclReferenceDumpExecutor()) + .withPostProcessingFunction(input + ? createInputAclFilter() + : createOutputAclFilter()) + .acceptOnly(AclInterfaceListDetailsReplyDump.class) + .build(); + + aclDumpManager = new DumpCacheManagerBuilder() + .withExecutor(createAclExecutor()) + .acceptOnly(AclDetailsReplyDump.class) + .build(); + } + + private EntityDumpExecutor createAclExecutor() { + return (identifier, params) -> { + AclDump request = new AclDump(); + request.aclIndex = params; + return getReplyForRead(getjVppAclFacade().aclDump(request).toCompletableFuture(), identifier); + }; + } + + private EntityDumpPostProcessingFunction createInputAclFilter() { + return dump -> { + // filters acl's to first N(those are input ones) + dump.aclInterfaceListDetails = dump.aclInterfaceListDetails + .stream() + .map(iface -> { + iface.acls = Arrays.copyOfRange(iface.acls, 0, iface.nInput - 1); + return iface; + }) + .collect(Collectors.toList()); + return dump; + }; + } + + private EntityDumpPostProcessingFunction createOutputAclFilter() { + return dump -> { + // filters acl's to last N(those are output ones) + dump.aclInterfaceListDetails = dump.aclInterfaceListDetails + .stream() + .map(iface -> { + iface.acls = Arrays.copyOfRange(iface.acls, iface.nInput, iface.acls.length); + return iface; + }) + .collect(Collectors.toList()); + return dump; + }; + } + + private EntityDumpExecutor createAclReferenceDumpExecutor() { + return (identifier, params) -> { + AclInterfaceListDump dumpRequest = new AclInterfaceListDump(); + dumpRequest.swIfIndex = params; + return getReplyForRead(getjVppAclFacade().aclInterfaceListDump(dumpRequest).toCompletableFuture(), + identifier); + }; + } + + @Nonnull + @Override + public List getAllIds(@Nonnull final InstanceIdentifier id, @Nonnull final ReadContext context) + throws ReadFailedException { + + final String parentInterfaceName = id.firstKeyOf(Interface.class).getName(); + final int parentInterfaceIndex = interfaceContext.getIndex(parentInterfaceName, context.getMappingContext()); + + final Optional dumpReply = + aclReferenceDumpManager.getDump(id, context.getModificationCache(), parentInterfaceIndex); + + if (dumpReply.isPresent() && !dumpReply.get().aclInterfaceListDetails.isEmpty()) { + return Arrays.stream(dumpReply.get().aclInterfaceListDetails.get(0).acls) + .mapToObj(aclIndex -> standardAclContext.getName(aclIndex, context.getMappingContext())) + .map(aclName -> new VppAclsKey(aclName, VppAcl.class)) + .collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + @Override + public void merge(@Nonnull final Builder builder, @Nonnull final List readData) { + if (input) { + IngressBuilder.class.cast(builder).setVppAcls(readData); + } else { + EgressBuilder.class.cast(builder).setVppAcls(readData); + } + } + + @Nonnull + @Override + public VppAclsBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new VppAclsBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VppAclsBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final VppAclsKey vppAclsKey = id.firstKeyOf(VppAcls.class); + final String aclName = vppAclsKey.getName(); + final int aclIndex = standardAclContext.getIndex(aclName, ctx.getMappingContext()); + + final Optional dumpReply = + aclDumpManager.getDump(id, ctx.getModificationCache(), aclIndex); + + if (dumpReply.isPresent() && !dumpReply.get().aclDetails.isEmpty()) { + // FIXME (model expects hex string, but tag is written and read as ascii string) + // decide how tag should be handled (model change might be needed). + builder.setName(aclName); + builder.setType(vppAclsKey.getType()); + builder.setTag(new HexString(printHexBinary(dumpReply.get().aclDetails.get(0).tag))); + } else { + throw new ReadFailedException(id, + new IllegalArgumentException(String.format("Acl with name %s not found", aclName))); + } + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java new file mode 100644 index 000000000..982d89b9a --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/VppMacIpAclCustomizer.java @@ -0,0 +1,143 @@ +/* + * 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.hc2vpp.acl.read; + +import static io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor.NO_PARAMS; + +import com.google.common.base.Optional; +import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.ModificationCache; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.spi.read.ReaderCustomizer; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.honeycomb.translate.util.read.cache.EntityDumpExecutor; +import io.fd.vpp.jvpp.acl.dto.MacipAclDetails; +import io.fd.vpp.jvpp.acl.dto.MacipAclDetailsReplyDump; +import io.fd.vpp.jvpp.acl.dto.MacipAclDump; +import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceGet; +import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceGetReply; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.HexString; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.IngressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAclBuilder; +import org.opendaylight.yangtools.concepts.Builder; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class VppMacIpAclCustomizer extends FutureJVppAclCustomizer + implements ReaderCustomizer, JvppReplyConsumer, ByteDataTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(VppMacIpAclCustomizer.class); + + private final DumpCacheManager macIpAclDumpManager; + private final DumpCacheManager interfaceMacIpAclDumpManager; + private final NamingContext interfaceContext; + private final NamingContext macIpAclContext; + + public VppMacIpAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext macIpAclContext) { + super(jVppAclFacade); + + // for dumping of Mac-ip details + macIpAclDumpManager = new DumpCacheManager.DumpCacheManagerBuilder() + .withExecutor(createMacIpDumpExecutor()) + .acceptOnly(MacipAclDetailsReplyDump.class) + .build(); + + // for dumping of reference on interface + interfaceMacIpAclDumpManager = new DumpCacheManager.DumpCacheManagerBuilder() + .withExecutor(createInterfaceMacIpDumpExecutor()) + .acceptOnly(MacipAclInterfaceGetReply.class) + .build(); + this.interfaceContext = interfaceContext; + this.macIpAclContext = macIpAclContext; + } + + private EntityDumpExecutor createMacIpDumpExecutor() { + return (identifier, params) -> { + MacipAclDump request = new MacipAclDump(); + request.aclIndex = params; + + return getReplyForRead(getjVppAclFacade().macipAclDump(request).toCompletableFuture(), identifier); + }; + } + + private EntityDumpExecutor createInterfaceMacIpDumpExecutor() { + return (identifier, params) -> getReplyForRead( + getjVppAclFacade().macipAclInterfaceGet(new MacipAclInterfaceGet()).toCompletableFuture(), + identifier); + } + + @Nonnull + @Override + public VppMacipAclBuilder getBuilder(@Nonnull final InstanceIdentifier id) { + return new VppMacipAclBuilder(); + } + + @Override + public void readCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VppMacipAclBuilder builder, + @Nonnull final ReadContext ctx) throws ReadFailedException { + final String interfaceName = id.firstKeyOf(Interface.class).getName(); + final MappingContext mappingContext = ctx.getMappingContext(); + final int interfaceIndex = interfaceContext.getIndex(interfaceName, mappingContext); + final ModificationCache modificationCache = ctx.getModificationCache(); + final Optional interfacesMacIpDumpReply = + interfaceMacIpAclDumpManager.getDump(id, modificationCache, NO_PARAMS); + + if (interfacesMacIpDumpReply.isPresent() && interfaceIndex < interfacesMacIpDumpReply.get().count) { + final int aclIndex = interfacesMacIpDumpReply.get().acls[interfaceIndex]; + + final Optional macIpDumpReply = + macIpAclDumpManager.getDump(id, modificationCache, aclIndex); + + if (macIpDumpReply.isPresent() && !macIpDumpReply.get().macipAclDetails.isEmpty()) { + final MacipAclDetails details = macIpDumpReply.get().macipAclDetails.get(0); + + builder.setName(macIpAclContext.getName(aclIndex, mappingContext)) + .setType( + org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAcl.class) + .setTag(new HexString(printHexBinary(details.tag))); + } else { + // this is invalid state(Interface in VPP will act as "deny-all" for security reasons), but generally + // it should not happen + throw new ReadFailedException(id, + new IllegalStateException(String.format("ACC with index %s not found in VPP", aclIndex))); + } + } else { + // this is valid state, so just logging + LOG.info("No Mac-ip ACL specified for Interface name={},index={}", interfaceName, interfaceIndex); + } + } + + @Override + public void merge(@Nonnull final Builder parentBuilder, + @Nonnull final VppMacipAcl readValue) { + IngressBuilder.class.cast(parentBuilder).setVppMacipAcl(readValue); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java new file mode 100644 index 000000000..89520620d --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/read/factory/InterfaceAclReaderFactory.java @@ -0,0 +1,85 @@ +/* + * 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.hc2vpp.acl.read.factory; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.hc2vpp.acl.AclModule; +import io.fd.hc2vpp.acl.read.VppAclCustomizer; +import io.fd.hc2vpp.acl.read.VppMacIpAclCustomizer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.impl.read.GenericListReader; +import io.fd.honeycomb.translate.impl.read.GenericReader; +import io.fd.honeycomb.translate.read.ReaderFactory; +import io.fd.honeycomb.translate.read.registry.ModifiableReaderRegistryBuilder; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceStateAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceStateAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.AclBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Egress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.EgressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.IngressBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfaceAclReaderFactory implements ReaderFactory { + + @Inject + private FutureJVppAclFacade futureAclFacade; + + @Inject + @Named(AclModule.STANDARD_ACL_CONTEXT_NAME) + private NamingContext standardAclContext; + + @Inject + @Named(AclModule.MAC_IP_ACL_CONTEXT_NAME) + private NamingContext macIpAClContext; + + @Inject + @Named("interface-context") + private NamingContext interfaceContext; + + private static final InstanceIdentifier + IFC_ID = InstanceIdentifier.create(InterfacesState.class).child(Interface.class); + private static final InstanceIdentifier VPP_ACL_AUG_IID = + IFC_ID.augmentation(VppAclInterfaceStateAugmentation.class); + private static final InstanceIdentifier ACL_IID = VPP_ACL_AUG_IID.child(Acl.class); + + @Override + public void init(@Nonnull final ModifiableReaderRegistryBuilder registry) { + registry.addStructuralReader(VPP_ACL_AUG_IID, VppAclInterfaceStateAugmentationBuilder.class); + registry.addStructuralReader(ACL_IID, AclBuilder.class); + + final InstanceIdentifier ingressInstanceIdentifier = ACL_IID.child(Ingress.class); + registry.addStructuralReader(ingressInstanceIdentifier, IngressBuilder.class); + registry.addAfter(new GenericListReader<>(ingressInstanceIdentifier.child(VppAcls.class), + new VppAclCustomizer(futureAclFacade, interfaceContext, standardAclContext, true)), IFC_ID); + registry.addAfter(new GenericReader<>(ingressInstanceIdentifier.child(VppMacipAcl.class), + new VppMacIpAclCustomizer(futureAclFacade, interfaceContext, macIpAClContext)), IFC_ID); + + final InstanceIdentifier egressInstanceIdentifier = ACL_IID.child(Egress.class); + registry.addStructuralReader(egressInstanceIdentifier, EgressBuilder.class); + registry.addAfter(new GenericListReader<>(egressInstanceIdentifier.child(VppAcls.class), + new VppAclCustomizer(futureAclFacade, interfaceContext, standardAclContext, false)), IFC_ID); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java new file mode 100644 index 000000000..e2d6bee58 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/FutureJVppAclCustomizer.java @@ -0,0 +1,38 @@ +/* + * 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.hc2vpp.acl.util; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; + +/** + * Holds reference to jvpp acl implementation + */ +public abstract class FutureJVppAclCustomizer { + + private final FutureJVppAclFacade jVppAclFacade; + + public FutureJVppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade) { + this.jVppAclFacade = checkNotNull(jVppAclFacade, "JVpp Acl Future api is null"); + } + + public FutureJVppAclFacade getjVppAclFacade() { + return jVppAclFacade; + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java new file mode 100644 index 000000000..325787821 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/AceConverter.java @@ -0,0 +1,94 @@ +/* + * 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.hc2vpp.acl.util.ace; + +import io.fd.hc2vpp.acl.util.ace.extractor.MacIpAceDataExtractor; +import io.fd.hc2vpp.acl.util.ace.extractor.StandardAceDataExtractor; +import io.fd.hc2vpp.acl.util.protocol.ProtoPreBindRuleProducer; +import io.fd.vpp.jvpp.acl.types.AclRule; +import io.fd.vpp.jvpp.acl.types.MacipAclRule; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nonnull; +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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce; + +/** + * Convert Ace's to vpp rules + */ +public interface AceConverter extends MacIpAceDataExtractor, StandardAceDataExtractor, ProtoPreBindRuleProducer { + + + default MacipAclRule[] convertToMacIpAclRules(@Nonnull final List aces) { + return aces.stream() + .map(ace -> { + final VppMacipAce macIpAce = fromMacIpAce(ace); + + MacipAclRule rule = new MacipAclRule(); + + rule.srcMac = sourceMacAsBytes(macIpAce); + rule.srcMacMask = sourceMacMaskAsBytes(macIpAce); + rule.isPermit = macIpAction(ace); + + if (macIpIsIpv6(macIpAce)) { + rule.isIpv6 = 1; + rule.srcIpAddr = ipv6Address(macIpAce); + rule.srcIpPrefixLen = ipv6AddressPrefix(macIpAce); + } else { + rule.isIpv6 = 0; + rule.srcIpAddr = ipv4Address(macIpAce); + rule.srcIpPrefixLen = ipv4AddressPrefix(macIpAce); + } + + return rule; + }) + .collect(Collectors.toList()) + .toArray(new MacipAclRule[aces.size()]); + } + + default AclRule[] convertToStandardAclRules(@Nonnull final List aces) { + return aces.stream() + .map(ace -> { + final VppAce standardAce = fromStandardAce(ace); + + // pre-bind rule with protocol based attributes + AclRule rule = createPreBindRule(standardAce); + + rule.isPermit = standardAction(ace); + + if (standardIsIpv6(ace)) { + rule.isIpv6 = 1; + rule.srcIpAddr = ipv6SourceAddress(standardAce); + rule.srcIpPrefixLen = ipv6SourceAddressPrefix(standardAce); + rule.dstIpAddr = ipv6DestinationAddress(standardAce); + rule.dstIpPrefixLen = ipv6DestinationAddressPrefix(standardAce); + } else { + rule.isIpv6 = 0; + rule.srcIpAddr = ipv4SourceAddress(standardAce); + rule.srcIpPrefixLen = ipv4SourceAddressPrefix(standardAce); + rule.dstIpAddr = ipv4DestinationAddress(standardAce); + rule.dstIpPrefixLen = ipv4DestinationAddressPrefix(standardAce); + } + + + return rule; + }) + .collect(Collectors.toList()) + .toArray(new AclRule[aces.size()]); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java new file mode 100644 index 000000000..a0d19902a --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/MacIpAceDataExtractor.java @@ -0,0 +1,83 @@ +/* + * 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.hc2vpp.acl.util.ace.extractor; + +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import javax.annotation.Nonnull; +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.actions.PacketHandling; +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.Deny; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAceIpv4HeaderFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAceIpv6HeaderFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv6; + +public interface MacIpAceDataExtractor extends AddressTranslator { + + default VppMacipAce fromMacIpAce(@Nonnull final Ace ace) { + return VppMacipAce.class.cast(ace.getMatches().getAceType()); + } + + default boolean macIpIsIpv6(@Nonnull final VppMacipAce ace) { + return ace.getVppMacipAceNodes().getAceIpVersion() instanceof AceIpv6; + } + + default byte[] sourceMacAsBytes(@Nonnull final VppMacipAce ace) { + return macToByteArray(ace.getVppMacipAceNodes().getSourceMacAddress().getValue()); + } + + default byte[] sourceMacMaskAsBytes(@Nonnull final VppMacipAce ace) { + return macToByteArray(ace.getVppMacipAceNodes().getSourceMacAddressMask().getValue()); + } + + default byte[] ipv4Address(@Nonnull final VppMacipAce ace) { + return ipv4AddressPrefixToArray( + VppMacipAceIpv4HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv4Network()); + } + + default byte ipv4AddressPrefix(@Nonnull final VppMacipAce ace) { + return extractPrefix( + VppMacipAceIpv4HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv4Network()); + } + + default byte[] ipv6Address(@Nonnull final VppMacipAce ace) { + return ipv6AddressPrefixToArray( + VppMacipAceIpv6HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv6Network()); + } + + default byte ipv6AddressPrefix(@Nonnull final VppMacipAce ace) { + return extractPrefix( + VppMacipAceIpv6HeaderFields.class.cast(ace.getVppMacipAceNodes().getAceIpVersion()).getSourceIpv6Network()); + } + + /** + * Only 0 and 1 are allowed for mac-ip + */ + default byte macIpAction(@Nonnull final Ace ace) { + final PacketHandling action = ace.getActions().getPacketHandling(); + if (action instanceof Permit) { + return 1; + } else if (action instanceof Deny) { + return 0; + } else { + throw new IllegalArgumentException( + String.format("Unsupported packet-handling action %s for ACE %s", action, ace)); + } + } + +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java new file mode 100644 index 000000000..2e7ccbdc7 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/ace/extractor/StandardAceDataExtractor.java @@ -0,0 +1,98 @@ +/* + * 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.hc2vpp.acl.util.ace.extractor; + + +import com.google.common.collect.ImmutableMap; +import io.fd.hc2vpp.acl.util.protocol.ProtoPreBindRuleProducer; +import io.fd.hc2vpp.common.translate.util.AddressTranslator; +import java.util.Map; +import javax.annotation.Nonnull; +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.actions.PacketHandling; +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.Deny; +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; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv4HeaderFields; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv6HeaderFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.actions.packet.handling.Stateful; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.vpp.ace.nodes.ace.ip.version.AceIpv6; + + +public interface StandardAceDataExtractor extends AddressTranslator, ProtoPreBindRuleProducer { + + /** + * Allowed packet-processing actions for Acl's + */ + Map, Integer> ACTION_VALUE_PAIRS = ImmutableMap.of(Deny.class, 0, Permit.class, 1, + Stateful.class, 2); + + default VppAce fromStandardAce(@Nonnull final Ace ace) { + return VppAce.class.cast(ace.getMatches().getAceType()); + } + + default boolean standardIsIpv6(@Nonnull final Ace ace) { + return VppAce.class.cast(ace.getMatches().getAceType()).getVppAceNodes().getAceIpVersion() instanceof AceIpv6; + } + + default byte[] ipv4SourceAddress(@Nonnull final VppAce ace) { + return ipv4AddressPrefixToArray( + AclIpv4HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv4Network()); + } + + default byte ipv4SourceAddressPrefix(@Nonnull final VppAce ace) { + return extractPrefix(AclIpv4HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv4Network()); + } + + default byte[] ipv4DestinationAddress(@Nonnull final VppAce ace) { + return ipv4AddressPrefixToArray( + AclIpv4HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv4Network()); + } + + default byte ipv4DestinationAddressPrefix(@Nonnull final VppAce ace) { + return extractPrefix(AceIpv4.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv4Network()); + } + + default byte[] ipv6SourceAddress(@Nonnull final VppAce ace) { + return ipv6AddressPrefixToArray( + AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv6Network()); + } + + default byte ipv6SourceAddressPrefix(@Nonnull final VppAce ace) { + return extractPrefix(AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getSourceIpv6Network()); + } + + default byte[] ipv6DestinationAddress(@Nonnull final VppAce ace) { + return ipv6AddressPrefixToArray( + AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv6Network()); + } + + default byte ipv6DestinationAddressPrefix(@Nonnull final VppAce ace) { + return extractPrefix(AclIpv6HeaderFields.class.cast(ace.getVppAceNodes().getAceIpVersion()).getDestinationIpv6Network()); + } + + default byte standardAction(@Nonnull final Ace ace) { + final PacketHandling action = ace.getActions().getPacketHandling(); + return ACTION_VALUE_PAIRS.get(ACTION_VALUE_PAIRS.keySet().stream() + .filter(aClass -> aClass.isInstance(action)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException( + String.format("Unsupported packet-handling action %s for ACE %s", action, + ace.getRuleName())))).byteValue(); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java new file mode 100644 index 000000000..77e58fe0c --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclDataExtractor.java @@ -0,0 +1,68 @@ +/* + * 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.hc2vpp.acl.util.acl; + +import java.nio.charset.StandardCharsets; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; +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; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce; + +/** + * Extracts data from Acls. + * Expects data validated by {@link AclValidator} + */ +public interface AclDataExtractor { + + /** + * Checks if provided {@link Acl} has aces of type {@link VppAce} + */ + default boolean isStandardAcl(@Nonnull final Acl acl) { + return acl.getAccessListEntries().getAce().stream() + .map(Ace::getMatches) + .map(Matches::getAceType) + .filter(aceType -> aceType instanceof VppAce) + .findAny() + .isPresent(); + } + + /** + * Checks if provided {@link Acl} has aces of type {@link VppMacipAce} + */ + default boolean isMacIpAcl(@Nonnull final Acl acl) { + return acl.getAccessListEntries().getAce().stream() + .map(Ace::getMatches) + .map(Matches::getAceType) + .filter(aceType -> aceType instanceof VppMacipAce) + .findAny() + .isPresent(); + } + + default List getAces(@Nonnull final Acl acl) { + return acl.getAccessListEntries().getAce(); + } + + /** + * Convert {@link Acl} name to byte array as UTF_8 + */ + default byte[] getAclNameAsBytes(@Nonnull final Acl acl) { + return acl.getAclName().getBytes(StandardCharsets.UTF_8); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java new file mode 100644 index 000000000..3779b82bf --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclValidator.java @@ -0,0 +1,84 @@ +/* + * 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.hc2vpp.acl.util.acl; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +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.Acl; +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; +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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppAcl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.VppMacipAcl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppMacipAce; + +/** + * Validate Acl data if processable by vpp + */ +public interface AclValidator { + + Set> SUPPORTED_ACL_TYPES = ImmutableSet.of(VppAcl.class, VppMacipAcl.class); + + Map, Class> ACL_ACE_PAIRS = ImmutableMap.of( + VppAcl.class, VppAce.class, + VppMacipAcl.class, VppMacipAce.class); + + static void isSupportedAclType(final Acl acl) { + checkArgument(SUPPORTED_ACL_TYPES.contains(acl.getAclType()), + "Unsupported Acl type %s detected for acl %s, allowed types are %s", acl.getAclType(), + acl.getAclName(), SUPPORTED_ACL_TYPES); + } + + static void hasConsistentAceTypeForAclType(final Acl acl) { + checkTypesSame(acl.getAccessListEntries().getAce(), acl.getAclName(), + checkNotNull(ACL_ACE_PAIRS.get(acl.getAclType()), "Unsupported ACL type %s for ACL %s", + acl.getAclType(), acl.getAclName())); + } + + static void checkTypesSame(final List aces, final String aclName, final Class aceType) { + final Set unsupportedAceTypes = aces.stream() + .map(Ace::getMatches) + .map(Matches::getAceType) + .filter(aceType::equals) + .collect(Collectors.toSet()); + checkArgument(unsupportedAceTypes.isEmpty(), "Detected unsupported ace types [%s] for ACL %s, expected %s", + unsupportedAceTypes, aclName, aceType); + } + + static void hasAceList(final Acl acl) { + //checks if aces are defined + checkArgument(!checkNotNull(checkNotNull(acl.getAccessListEntries(), "No access list entries defined") + .getAce(), "No aces defined") + .isEmpty(), "Empty ace list defined"); + } + + default void validateAcl(@Nonnull final Acl acl) { + hasAceList(acl); + isSupportedAclType(acl); + hasConsistentAceTypeForAclType(acl); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java new file mode 100644 index 000000000..1fecc6c5b --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/acl/AclWriter.java @@ -0,0 +1,125 @@ +/* + * 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.hc2vpp.acl.util.acl; + +import io.fd.hc2vpp.acl.util.ace.AceConverter; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.dto.AclAddReplace; +import io.fd.vpp.jvpp.acl.dto.AclAddReplaceReply; +import io.fd.vpp.jvpp.acl.dto.AclDel; +import io.fd.vpp.jvpp.acl.dto.MacipAclAdd; +import io.fd.vpp.jvpp.acl.dto.MacipAclAddReply; +import io.fd.vpp.jvpp.acl.dto.MacipAclDel; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Write standard and mac-ip acls + */ +public interface AclWriter extends AclDataExtractor, AceConverter, JvppReplyConsumer { + + int ACL_INDEX_CREATE_NEW = -1; + + default void addStandardAcl(@Nonnull final FutureJVppAclFacade futureFacade, + @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final NamingContext standardAclContext, + @Nonnull final MappingContext mappingContext) throws WriteFailedException { + + final AclAddReplace request = new AclAddReplace(); + + request.tag = getAclNameAsBytes(acl); + request.aclIndex = ACL_INDEX_CREATE_NEW; + request.r = convertToStandardAclRules(getAces(acl)); + request.count = request.r.length; + + final AclAddReplaceReply reply = + getReplyForWrite(futureFacade.aclAddReplace(request).toCompletableFuture(), id); + + // maps new acl to returned index + standardAclContext.addName(reply.aclIndex, acl.getAclName(), mappingContext); + } + + // according to vpp team, this was tested extensively, and should work + default void updateStandardAcl(@Nonnull final FutureJVppAclFacade futureFacade, + @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final NamingContext standardAclContext, + @Nonnull final MappingContext mappingContext) throws WriteFailedException { + + final AclAddReplace request = new AclAddReplace(); + + request.tag = getAclNameAsBytes(acl); + // by setting existing index, request is resolved as update + request.aclIndex = standardAclContext.getIndex(acl.getAclName(), mappingContext); + request.r = convertToStandardAclRules(getAces(acl)); + request.count = request.r.length; + + getReplyForWrite(futureFacade.aclAddReplace(request).toCompletableFuture(), id); + + } + + + default void deleteStandardAcl(@Nonnull final FutureJVppAclFacade futureFacade, + @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final NamingContext standardAclContext, + @Nonnull final MappingContext mappingContext) throws WriteFailedException { + + final AclDel request = new AclDel(); + final String aclName = acl.getAclName(); + request.aclIndex = standardAclContext.getIndex(aclName, mappingContext); + + getReplyForDelete(futureFacade.aclDel(request).toCompletableFuture(), id); + + // removes mapping after successful delete + standardAclContext.removeName(aclName, mappingContext); + } + + default void addMacIpAcl(@Nonnull final FutureJVppAclFacade futureFacade, + @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final NamingContext macIpAclContext, + @Nonnull final MappingContext mappingContext) throws WriteFailedException { + final MacipAclAdd request = new MacipAclAdd(); + + request.tag = getAclNameAsBytes(acl); + request.r = convertToMacIpAclRules(getAces(acl)); + request.count = request.r.length; + + final MacipAclAddReply reply = getReplyForWrite(futureFacade.macipAclAdd(request).toCompletableFuture(), id); + + // map mac-ip acl to returned index + macIpAclContext.addName(reply.aclIndex, acl.getAclName(), mappingContext); + } + + default void deleteMacIpAcl(@Nonnull final FutureJVppAclFacade futureFacade, + @Nonnull final InstanceIdentifier id, @Nonnull final Acl acl, + @Nonnull final NamingContext macIpAclContext, + @Nonnull final MappingContext mappingContext) throws WriteFailedException { + final MacipAclDel request = new MacipAclDel(); + final String aclName = acl.getAclName(); + request.aclIndex = macIpAclContext.getIndex(aclName, mappingContext); + + getReplyForDelete(futureFacade.macipAclDel(request).toCompletableFuture(), id); + + macIpAclContext.removeName(aclName, mappingContext); + } + + +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java new file mode 100644 index 000000000..e3c5b727e --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/acl/AclInterfaceAssignmentRequest.java @@ -0,0 +1,162 @@ +/* + * 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.hc2vpp.acl.util.iface.acl; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.dto.AclInterfaceSetAclList; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.util.List; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Multi-assignment single-request taking advantage from acl_interface_set_acl_list api + */ +public class AclInterfaceAssignmentRequest implements JvppReplyConsumer, ByteDataTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(AclInterfaceAssignmentRequest.class); + + private final MappingContext mappingContext; + private InstanceIdentifier identifier; + private List inputAclNames; + private List outputAclNames; + private NamingContext standardAclContext; + private NamingContext interfaceContext; + + + private AclInterfaceAssignmentRequest(final MappingContext mappingContext) { + this.mappingContext = checkNotNull(mappingContext, "Mapping context cannot be null"); + } + + public static AclInterfaceAssignmentRequest create(@Nonnull final MappingContext mappingContext) { + return new AclInterfaceAssignmentRequest(mappingContext); + } + + public AclInterfaceAssignmentRequest identifier( + @Nonnull final InstanceIdentifier identifier) { + this.identifier = identifier; + return this; + } + + public AclInterfaceAssignmentRequest inputAclNames(@Nonnull final List inputAclNames) { + this.inputAclNames = inputAclNames; + return this; + } + + public AclInterfaceAssignmentRequest outputAclNames(@Nonnull final List outputAclNames) { + this.outputAclNames = outputAclNames; + return this; + } + + public AclInterfaceAssignmentRequest standardAclContext(@Nonnull final NamingContext standardAclContext) { + this.standardAclContext = standardAclContext; + return this; + } + + public AclInterfaceAssignmentRequest interfaceContext(@Nonnull final NamingContext interfaceContext) { + this.interfaceContext = interfaceContext; + return this; + } + + private void checkValidRequest() { + checkNotNull(identifier, "Identifier cannot be null"); + checkNotNull(inputAclNames, "Input ACL names cannot be null"); + checkNotNull(outputAclNames, "Output ACL names cannot be null"); + checkNotNull(standardAclContext, "ACL context cannot be null"); + checkNotNull(interfaceContext, "Interface context cannot be null"); + } + + public void executeAsCreate(@Nonnull final FutureJVppAclFacade api) throws WriteFailedException { + checkValidRequest(); + final String interfaceName = identifier.firstKeyOf(Interface.class).getName(); + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request + synchronized (mappingContext) { + LOG.debug( + "Executing acl interface assignment write request for interface={}, input ACL's={},output ACL's={}", + interfaceName, inputAclNames, outputAclNames); + + getReplyForWrite(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(), + identifier); + LOG.debug( + "Acl interface assignment write request for interface={}, input ACL's={},output ACL's={} successfully passed", + interfaceName, inputAclNames, outputAclNames); + } + } + + public void executeAsUpdate(@Nonnull final FutureJVppAclFacade api, final Acl before, final Acl after) + throws WriteFailedException { + checkValidRequest(); + final String interfaceName = identifier.firstKeyOf(Interface.class).getName(); + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request + synchronized (mappingContext) { + LOG.debug( + "Executing acl interface assignment update request for interface={}, input ACL's={},output ACL's={}", + interfaceName, inputAclNames, outputAclNames); + + getReplyForUpdate(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(), + identifier, before, after); + LOG.debug( + "Acl interface assignment update request for interface={}, input ACL's={},output ACL's={} successfully passed", + interfaceName, inputAclNames, outputAclNames); + } + } + + public void executeAsDelete(@Nonnull final FutureJVppAclFacade api) throws WriteFailedException { + checkValidRequest(); + final String interfaceName = identifier.firstKeyOf(Interface.class).getName(); + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during binding/execution of request + synchronized (mappingContext) { + LOG.debug( + "Executing acl interface assignment delete request for interface={}, input ACL's={},output ACL's={}", + interfaceName, inputAclNames, outputAclNames); + + getReplyForDelete(api.aclInterfaceSetAclList(createRequest(interfaceName)).toCompletableFuture(), + identifier); + LOG.debug( + "Acl interface assignment delete request for interface={}, input ACL's={},output ACL's={} successfully passed", + interfaceName, inputAclNames, outputAclNames); + } + } + + // synchronized on higher layer + private AclInterfaceSetAclList createRequest(final String interfaceName) { + + AclInterfaceSetAclList request = new AclInterfaceSetAclList(); + request.swIfIndex = interfaceContext.getIndex(interfaceName, mappingContext); + request.nInput = (byte) inputAclNames.size(); + request.count = (byte) (inputAclNames.size() + outputAclNames.size()); + request.acls = Stream.concat(inputAclNames.stream(), outputAclNames.stream()) + .mapToInt(aclName -> standardAclContext.getIndex(aclName, mappingContext)) + .toArray(); + return request; + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java new file mode 100644 index 000000000..f8d726397 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/iface/macip/MacIpInterfaceAssignmentRequest.java @@ -0,0 +1,111 @@ +/* + * 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.hc2vpp.acl.util.iface.macip; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.fd.hc2vpp.common.translate.util.ByteDataTranslator; +import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.dto.MacipAclInterfaceAddDel; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MacIpInterfaceAssignmentRequest implements ByteDataTranslator, JvppReplyConsumer { + + private static final Logger LOG = LoggerFactory.getLogger(MacIpInterfaceAssignmentRequest.class); + + private final boolean isNew; + private final MappingContext mappingContext; + private InstanceIdentifier identifier; + private String aclName; + private NamingContext macIpAclContext; + private NamingContext interfaceContext; + + + private MacIpInterfaceAssignmentRequest(final boolean isNew, final MappingContext mappingContext) { + this.isNew = isNew; + this.mappingContext = checkNotNull(mappingContext, "Mapping context cannot be null"); + } + + public static MacIpInterfaceAssignmentRequest addNew(@Nonnull final MappingContext mappingContext) { + return new MacIpInterfaceAssignmentRequest(true, mappingContext); + } + + public static MacIpInterfaceAssignmentRequest deleteExisting(@Nonnull final MappingContext mappingContext) { + return new MacIpInterfaceAssignmentRequest(false, mappingContext); + } + + public MacIpInterfaceAssignmentRequest identifier(@Nonnull final InstanceIdentifier identifier) { + this.identifier = identifier; + return this; + } + + public MacIpInterfaceAssignmentRequest aclName(@Nonnull final String aclName) { + this.aclName = aclName; + return this; + } + + public MacIpInterfaceAssignmentRequest macIpAclContext(@Nonnull final NamingContext macIpAclContext) { + this.macIpAclContext = macIpAclContext; + return this; + } + + public MacIpInterfaceAssignmentRequest interfaceContext(@Nonnull final NamingContext interfaceContext) { + this.interfaceContext = interfaceContext; + return this; + } + + private void checkValidRequest() { + checkNotNull(identifier, "Identifier cannot be null"); + checkNotNull(aclName, "ACL name cannot be null"); + checkNotNull(macIpAclContext, "ACL context cannot be null"); + checkNotNull(interfaceContext, "Interface context cannot be null"); + } + + public void execute(@Nonnull final FutureJVppAclFacade api) + throws WriteFailedException { + + // locking on mapping context, to prevent modifying of mappings (for both contexts) during execution of request + synchronized (mappingContext) { + checkValidRequest(); + + final String interfaceName = identifier.firstKeyOf(Interface.class).getName(); + + MacipAclInterfaceAddDel request = new MacipAclInterfaceAddDel(); + request.isAdd = booleanToByte(isNew); + request.aclIndex = macIpAclContext.getIndex(aclName, mappingContext); + request.swIfIndex = + interfaceContext.getIndex(interfaceName, mappingContext); + + LOG.debug("Executing mac-ip interface assignment request for isNew={},aclName={},interfaceName={}", isNew, + aclName, interfaceName); + getReplyForWrite(api.macipAclInterfaceAddDel(request).toCompletableFuture(), identifier); + LOG.debug( + "Mac-ip interface assignment request for isNew={},aclName={},interfaceName={} successfully passed", + isNew, aclName, interfaceName); + } + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java new file mode 100644 index 000000000..c1f9a40ff --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/util/protocol/ProtoPreBindRuleProducer.java @@ -0,0 +1,203 @@ +/* + * 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.hc2vpp.acl.util.protocol; + +import static com.google.common.base.Preconditions.checkArgument; +import static io.fd.hc2vpp.acl.util.protocol.ProtoPreBindRuleProducer.ProtocolPair.pair; + +import com.google.common.collect.ImmutableSet; +import io.fd.vpp.jvpp.acl.types.AclRule; +import java.util.Optional; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ValueRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.VppAce; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.VppAceNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.IpProtocol; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Icmp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.IcmpV6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Other; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Tcp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.Udp; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.IcmpNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.v6.IcmpV6Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.tcp.TcpNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.udp.UdpNodes; + +/** + * Creates ACL rules pre-bind with protocol-related fields.
+ * Support TCP, UDP, ICMP and ICMPv6 protocol numbers according to + * this document + */ +public interface ProtoPreBindRuleProducer { + + int ICMP_INDEX = 1; + int TCP_INDEX = 6; + int UDP_INDEX = 17; + int ICMPV6_INDEX = 58; + + Set PROTOCOL_PAIRS = ImmutableSet.of(pair(Icmp.class, ICMP_INDEX), pair(Tcp.class, TCP_INDEX), + pair(Udp.class, UDP_INDEX), pair(IcmpV6.class, ICMPV6_INDEX)); + + class ProtocolPair { + private final Class protocolClass; + private final int index; + + private ProtocolPair(final Class protocolClass, final int index) { + this.protocolClass = protocolClass; + this.index = index; + } + + static ProtocolPair pair(@Nonnull final Class protocolClass, @Nonnull final int index) { + return new ProtocolPair(protocolClass, index); + } + + boolean match(@Nonnull final Class protocolClass) { + return this.protocolClass.isAssignableFrom(protocolClass); + } + + int getIndex() { + return this.index; + } + } + + static byte protocol(final IpProtocol ipProtocol) { + final Optional optPair = PROTOCOL_PAIRS.stream() + .filter(protocolPair -> protocolPair.match(ipProtocol.getClass())) + .findAny(); + + if (!optPair.isPresent()) { + if (Other.class.isAssignableFrom(ipProtocol.getClass())) { + return Other.class.cast(ipProtocol).getOtherNodes().getProtocol().byteValue(); + } + + throw new IllegalArgumentException(String.format("Unsupported Protocol Type %s", ipProtocol.getClass())); + } + return (byte) optPair.get().getIndex(); + } + + static AclRule bindIcmpNodes(AclRule rule, VppAce ace) { + final VppAceNodes vppAceNodes = ace.getVppAceNodes(); + checkArgument(vppAceNodes.getIpProtocol() instanceof Icmp); + final IcmpNodes icmp = Icmp.class.cast(vppAceNodes.getIpProtocol()).getIcmpNodes(); + final ValueRange typesRange = icmp.getIcmpTypeRange(); + final ValueRange codesRange = icmp.getIcmpCodeRange(); + + rule.srcportOrIcmptypeFirst = typesRange.getFirst(); + rule.srcportOrIcmptypeLast = typesRange.getLast(); + rule.dstportOrIcmpcodeFirst = codesRange.getFirst(); + rule.dstportOrIcmpcodeLast = codesRange.getLast(); + + return rule; + } + + static AclRule bindIcmpv6Nodes(AclRule rule, VppAce ace) { + final VppAceNodes vppAceNodes = ace.getVppAceNodes(); + checkArgument(vppAceNodes.getIpProtocol() instanceof IcmpV6); + final IcmpV6Nodes icmpV6 = IcmpV6.class.cast(vppAceNodes.getIpProtocol()).getIcmpV6Nodes(); + final ValueRange typesRange = icmpV6.getIcmpTypeRange(); + final ValueRange codesRange = icmpV6.getIcmpCodeRange(); + + rule.srcportOrIcmptypeFirst = typesRange.getFirst(); + rule.srcportOrIcmptypeLast = typesRange.getLast(); + rule.dstportOrIcmpcodeFirst = codesRange.getFirst(); + rule.dstportOrIcmpcodeLast = codesRange.getLast(); + + return rule; + } + + + static AclRule bindTcpNodes(AclRule rule, VppAce ace) { + final VppAceNodes vppAceNodes = ace.getVppAceNodes(); + checkArgument(vppAceNodes.getIpProtocol() instanceof Tcp); + + final TcpNodes tcp = Tcp.class.cast(vppAceNodes.getIpProtocol()).getTcpNodes(); + final SourcePortRange sourcePortRange = tcp.getSourcePortRange(); + final DestinationPortRange destinationPortRange = tcp.getDestinationPortRange(); + + rule.srcportOrIcmptypeFirst = portNumber(sourcePortRange.getLowerPort()); + rule.srcportOrIcmptypeLast = portNumber(sourcePortRange.getUpperPort()); + rule.dstportOrIcmpcodeFirst = portNumber(destinationPortRange.getLowerPort()); + rule.dstportOrIcmpcodeLast = portNumber(destinationPortRange.getUpperPort()); + rule.tcpFlagsMask = tcp.getTcpFlagsMask().byteValue(); + rule.tcpFlagsValue = tcp.getTcpFlagsValue().byteValue(); + + return rule; + } + + static AclRule bindUdpNodes(AclRule rule, VppAce ace) { + final VppAceNodes vppAceNodes = ace.getVppAceNodes(); + checkArgument(vppAceNodes.getIpProtocol() instanceof Udp); + + final UdpNodes udp = Udp.class.cast(vppAceNodes.getIpProtocol()).getUdpNodes(); + final SourcePortRange sourcePortRange = udp.getSourcePortRange(); + final DestinationPortRange destinationPortRange = udp.getDestinationPortRange(); + + rule.srcportOrIcmptypeFirst = portNumber(sourcePortRange.getLowerPort()); + rule.srcportOrIcmptypeLast = portNumber(sourcePortRange.getUpperPort()); + rule.dstportOrIcmpcodeFirst = portNumber(destinationPortRange.getLowerPort()); + rule.dstportOrIcmpcodeLast = portNumber(destinationPortRange.getUpperPort()); + + return rule; + } + + static AclRule bindDefaultNodes(AclRule rule) { + rule.srcportOrIcmptypeFirst = 0; + rule.srcportOrIcmptypeLast = (short) 65535; + rule.dstportOrIcmpcodeFirst = 0; + rule.dstportOrIcmpcodeLast = (short) 65535; + rule.tcpFlagsValue = 0; + rule.tcpFlagsMask = 0; + return rule; + } + + static short portNumber(final PortNumber portNumber) { + return portNumber.getValue().shortValue(); + } + + default AclRule createPreBindRule(@Nonnull final VppAce vppAce) { + AclRule rule = new AclRule(); + + rule.proto = protocol(vppAce.getVppAceNodes().getIpProtocol()); + + switch (rule.proto) { + case ICMP_INDEX: { + return bindIcmpNodes(rule, vppAce); + } + + case TCP_INDEX: { + return bindTcpNodes(rule, vppAce); + } + + case UDP_INDEX: { + return bindUdpNodes(rule, vppAce); + } + + case ICMPV6_INDEX: { + return bindIcmpv6Nodes(rule, vppAce); + } + default: { + return bindDefaultNodes(rule); + } + } + + } + +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java new file mode 100644 index 000000000..3a4fb0cf3 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclCustomizer.java @@ -0,0 +1,98 @@ +/* + * 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.hc2vpp.acl.write; + +import static java.util.stream.Collectors.toList; + +import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; +import io.fd.hc2vpp.acl.util.iface.acl.AclInterfaceAssignmentRequest; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclsBaseAttributes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Handles acl assignments(only standard ones, mac-ip have dedicated customizer) + */ +public class InterfaceAclCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer { + + private final NamingContext interfaceContext; + private final NamingContext standardAclContext; + + public InterfaceAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, + @Nonnull final NamingContext interfaceContext, + @Nonnull final NamingContext standardAclContext) { + super(jVppAclFacade); + this.interfaceContext = interfaceContext; + this.standardAclContext = standardAclContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) + .standardAclContext(standardAclContext) + .interfaceContext(interfaceContext) + .identifier(id) + .inputAclNames(getAclNames(dataAfter.getIngress())) + .outputAclNames(getAclNames(dataAfter.getEgress())) + .executeAsCreate(getjVppAclFacade()); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) + .standardAclContext(standardAclContext) + .interfaceContext(interfaceContext) + .identifier(id) + .inputAclNames(getAclNames(dataAfter.getIngress())) + .outputAclNames(getAclNames(dataAfter.getEgress())) + .executeAsUpdate(getjVppAclFacade(), dataBefore, dataAfter); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + AclInterfaceAssignmentRequest.create(writeContext.getMappingContext()) + .standardAclContext(standardAclContext) + .interfaceContext(interfaceContext) + .identifier(id) + .inputAclNames(getAclNames(dataBefore.getIngress())) + .outputAclNames(getAclNames(dataBefore.getEgress())) + .executeAsDelete(getjVppAclFacade()); + } + + private static List getAclNames(@Nonnull final VppAclsBaseAttributes acls) { + if (acls == null || acls.getVppAcls() == null) { + return Collections.emptyList(); + } else { + return acls.getVppAcls().stream().map(VppAcls::getName).collect(toList()); + } + } + + +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java new file mode 100644 index 000000000..4b59c83f5 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/InterfaceAclMacIpCustomizer.java @@ -0,0 +1,78 @@ +/* + * 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.hc2vpp.acl.write; + +import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.addNew; +import static io.fd.hc2vpp.acl.util.iface.macip.MacIpInterfaceAssignmentRequest.deleteExisting; + +import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.spi.write.WriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + + +public class InterfaceAclMacIpCustomizer extends FutureJVppAclCustomizer implements WriterCustomizer { + + private final NamingContext macIpAclContext; + private final NamingContext interfaceContext; + + public InterfaceAclMacIpCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, + @Nonnull final NamingContext macIpAclContext, + @Nonnull final NamingContext interfaceContext) { + super(jVppAclFacade); + this.macIpAclContext = macIpAclContext; + this.interfaceContext = interfaceContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VppMacipAcl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + addNew(writeContext.getMappingContext()) + .identifier(id) + .aclName(dataAfter.getName()) + .macIpAclContext(macIpAclContext) + .interfaceContext(interfaceContext) + .execute(getjVppAclFacade()); + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VppMacipAcl dataBefore, + @Nonnull final VppMacipAcl dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, + new UnsupportedOperationException("Operation not supported")); + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, + @Nonnull final VppMacipAcl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + deleteExisting(writeContext.getMappingContext()) + .identifier(id) + .aclName(dataBefore.getName()) + .macIpAclContext(macIpAclContext) + .interfaceContext(interfaceContext) + .execute(getjVppAclFacade()); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java new file mode 100644 index 000000000..a2956784f --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/VppAclCustomizer.java @@ -0,0 +1,110 @@ +/* + * 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.hc2vpp.acl.write; + +import io.fd.hc2vpp.acl.util.FutureJVppAclCustomizer; +import io.fd.hc2vpp.acl.util.acl.AclDataExtractor; +import io.fd.hc2vpp.acl.util.acl.AclValidator; +import io.fd.hc2vpp.acl.util.acl.AclWriter; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.honeycomb.translate.MappingContext; +import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VppAclCustomizer extends FutureJVppAclCustomizer + implements ListWriterCustomizer, AclValidator, AclDataExtractor, AclWriter { + + private final NamingContext standardAclContext; + private final NamingContext macIpAclContext; + + public VppAclCustomizer(@Nonnull final FutureJVppAclFacade jVppAclFacade, + @Nonnull final NamingContext standardAclContext, + @Nonnull final NamingContext macIpAclContext) { + super(jVppAclFacade); + this.standardAclContext = standardAclContext; + this.macIpAclContext = macIpAclContext; + } + + @Override + public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataAfter, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + validateAcl(dataAfter); + + final MappingContext mappingContext = writeContext.getMappingContext(); + + if (isStandardAcl(dataAfter)) { + addStandardAcl(getjVppAclFacade(), id, dataAfter, standardAclContext, mappingContext); + } else if (isMacIpAcl(dataAfter)) { + addMacIpAcl(getjVppAclFacade(), id, dataAfter, macIpAclContext, mappingContext); + } else { + // double check, first one done by validation + throw new WriteFailedException.CreateFailedException(id, dataAfter, + new IllegalArgumentException("Unsupported acl option")); + } + } + + @Override + public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final Acl dataAfter, @Nonnull final WriteContext writeContext) + throws WriteFailedException { + validateAcl(dataAfter); + + final MappingContext mappingContext = writeContext.getMappingContext(); + + if (isStandardAcl(dataAfter)) { + updateStandardAcl(getjVppAclFacade(), id, dataAfter, standardAclContext, mappingContext); + } else if (isMacIpAcl(dataAfter)) { + synchronized (macIpAclContext) { + // there is no direct support for update of mac-ip acl, but only one is allowed per interface + // so it is atomic from vpp standpoint. Enclosed in synchronized block to prevent issues with + // multiple threads managing naming context + deleteMacIpAcl(getjVppAclFacade(), id, dataBefore, macIpAclContext, mappingContext); + addMacIpAcl(getjVppAclFacade(), id, dataAfter, macIpAclContext, mappingContext); + } + } else { + // double check, first one done by validation + throw new WriteFailedException.CreateFailedException(id, dataAfter, + new IllegalArgumentException("Unsupported acl option")); + } + } + + @Override + public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Acl dataBefore, + @Nonnull final WriteContext writeContext) throws WriteFailedException { + // According to VPP team, acl references should be removed before trying to remove ACL + // For mac-ip, reference should be removed during removal of mac-ip, so no need to check in hc + validateAcl(dataBefore); + + final MappingContext mappingContext = writeContext.getMappingContext(); + + if (isStandardAcl(dataBefore)) { + deleteStandardAcl(getjVppAclFacade(), id, dataBefore, standardAclContext, mappingContext); + } else if (isMacIpAcl(dataBefore)) { + deleteMacIpAcl(getjVppAclFacade(), id, dataBefore, macIpAclContext, mappingContext); + } else { + // double check, first one done by validation + throw new WriteFailedException.DeleteFailedException(id, + new IllegalArgumentException("Unsupported acl option")); + } + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java new file mode 100644 index 000000000..fe22f2fd7 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/AbstractAclWriterFactory.java @@ -0,0 +1,44 @@ +/* + * 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.hc2vpp.acl.write.factory; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import io.fd.hc2vpp.acl.AclModule; +import io.fd.hc2vpp.common.translate.util.NamingContext; +import io.fd.vpp.jvpp.acl.future.FutureJVppAclFacade; + +/** + * Created by jsrnicek on 12.12.2016. + */ +class AbstractAclWriterFactory { + + @Inject + protected FutureJVppAclFacade futureAclFacade; + + @Inject + @Named(AclModule.STANDARD_ACL_CONTEXT_NAME) + protected NamingContext standardAclContext; + + @Inject + @Named(AclModule.MAC_IP_ACL_CONTEXT_NAME) + protected NamingContext macIpAClContext; + + @Inject + @Named("interface-context") + protected NamingContext interfaceContext; +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java new file mode 100644 index 000000000..6598aae9c --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/InterfaceAclWriterFactory.java @@ -0,0 +1,59 @@ +/* + * 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.hc2vpp.acl.write.factory; + +import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.acl.write.InterfaceAclCustomizer; +import io.fd.hc2vpp.acl.write.InterfaceAclMacIpCustomizer; +import io.fd.honeycomb.translate.impl.write.GenericWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.VppAclInterfaceAugmentation; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Egress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214._interface.acl.attributes.acl.Ingress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.acls.base.attributes.VppAcls; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang._interface.acl.rev161214.vpp.macip.acls.base.attributes.VppMacipAcl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class InterfaceAclWriterFactory extends AbstractAclWriterFactory implements WriterFactory { + + private static final InstanceIdentifier ACL_IID = + InstanceIdentifier.create(Interfaces.class).child(Interface.class) + .augmentation(VppAclInterfaceAugmentation.class).child(Acl.class); + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + registry.subtreeAdd(aclHandledChildren(InstanceIdentifier.create(Acl.class)), + new GenericWriter<>(ACL_IID, + new InterfaceAclCustomizer(futureAclFacade, interfaceContext, standardAclContext))); + + registry.add(new GenericWriter<>(ACL_IID.child(Ingress.class).child(VppMacipAcl.class), + new InterfaceAclMacIpCustomizer(futureAclFacade, macIpAClContext, interfaceContext))); + } + + private Set> aclHandledChildren(final InstanceIdentifier parentId) { + return ImmutableSet.of(parentId.child(Ingress.class), + parentId.child(Ingress.class).child(VppAcls.class), + parentId.child(Egress.class), + parentId.child(Egress.class).child(VppAcls.class)); + } +} diff --git a/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java new file mode 100644 index 000000000..546924ee3 --- /dev/null +++ b/acl/acl-impl/src/main/java/io/fd/hc2vpp/acl/write/factory/VppAclWriterFactory.java @@ -0,0 +1,82 @@ +/* + * 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.hc2vpp.acl.write.factory; + +import com.google.common.collect.ImmutableSet; +import io.fd.hc2vpp.acl.write.VppAclCustomizer; +import io.fd.honeycomb.translate.impl.write.GenericListWriter; +import io.fd.honeycomb.translate.write.WriterFactory; +import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AccessLists; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl; +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.Actions; +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; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.DestinationPortRange; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.ace.VppAceNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.vpp.macip.ace.VppMacipAceNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.icmp.header.fields.IcmpCodeRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.icmp.header.fields.IcmpTypeRange; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.IcmpNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.icmp.v6.IcmpV6Nodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.other.OtherNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.tcp.TcpNodes; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.ip.protocol.header.fields.ip.protocol.udp.UdpNodes; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public class VppAclWriterFactory extends AbstractAclWriterFactory implements WriterFactory { + + private static Set> vppAclCustomizerHandledChildren(final InstanceIdentifier parentId) { + final InstanceIdentifier matchesIid = + parentId.child(AccessListEntries.class).child(Ace.class).child(Matches.class); + return ImmutableSet.of(parentId.child(AccessListEntries.class), + parentId.child(AccessListEntries.class).child(Ace.class), + parentId.child(AccessListEntries.class).child(Ace.class).child(Matches.class), + parentId.child(AccessListEntries.class).child(Ace.class).child(Actions.class), + matchesIid, + matchesIid.child(VppMacipAceNodes.class), + matchesIid.child(VppAceNodes.class), + matchesIid.child(VppAceNodes.class).child(IcmpNodes.class), + matchesIid.child(VppAceNodes.class).child(IcmpNodes.class).child(IcmpCodeRange.class), + matchesIid.child(VppAceNodes.class).child(IcmpNodes.class).child(IcmpTypeRange.class), + matchesIid.child(VppAceNodes.class).child(IcmpV6Nodes.class), + matchesIid.child(VppAceNodes.class).child(IcmpV6Nodes.class).child(IcmpCodeRange.class), + matchesIid.child(VppAceNodes.class).child(IcmpV6Nodes.class).child(IcmpTypeRange.class), + matchesIid.child(VppAceNodes.class).child(UdpNodes.class), + matchesIid.child(VppAceNodes.class).child(UdpNodes.class).child(SourcePortRange.class), + matchesIid.child(VppAceNodes.class).child(UdpNodes.class).child(DestinationPortRange.class), + matchesIid.child(VppAceNodes.class).child(TcpNodes.class), + matchesIid.child(VppAceNodes.class).child(TcpNodes.class).child(SourcePortRange.class), + matchesIid.child(VppAceNodes.class).child(TcpNodes.class).child(DestinationPortRange.class), + matchesIid.child(VppAceNodes.class).child(OtherNodes.class) + + ); + } + + @Override + public void init(@Nonnull final ModifiableWriterRegistryBuilder registry) { + final InstanceIdentifier rootNode = InstanceIdentifier.create(AccessLists.class); + + registry.subtreeAdd(vppAclCustomizerHandledChildren(InstanceIdentifier.create(Acl.class)), + new GenericListWriter<>(rootNode.child(Acl.class), + new VppAclCustomizer(futureAclFacade, standardAclContext, macIpAClContext))); + } +} -- cgit 1.2.3-korg