From b9191c1a856d4f0c89a63a20c3927a95ab7e1bdc Mon Sep 17 00:00:00 2001 From: Marek Gradzki Date: Fri, 14 Oct 2016 14:52:39 +0200 Subject: HONEYCOMB-234: L2 egress ACL support Change-Id: I2912f1265af7487ceed1be01ac489ba765311a97 Signed-off-by: Marek Gradzki --- .../v3po/EgressIetfAClWriterProvider.java | 37 +++ .../translate/v3po/IetfAClWriterProvider.java | 37 --- .../v3po/IngressIetfAClWriterProvider.java | 37 +++ .../translate/v3po/InterfacesWriterFactory.java | 28 +- .../SubinterfaceAugmentationWriterFactory.java | 23 +- .../io/fd/honeycomb/translate/v3po/V3poModule.java | 8 +- .../acl/common/AbstractIetfAclWriter.java | 243 ++++++++++++++++ .../v3po/interfaces/acl/common/AceEthWriter.java | 85 ++++++ .../v3po/interfaces/acl/common/AceIp4Writer.java | 94 ++++++ .../v3po/interfaces/acl/common/AceIp6Writer.java | 99 +++++++ .../interfaces/acl/common/AceIpAndEthWriter.java | 129 +++++++++ .../v3po/interfaces/acl/common/AceWriter.java | 54 ++++ .../v3po/interfaces/acl/common/AclTranslator.java | 74 +++++ .../v3po/interfaces/acl/common/IetfAclWriter.java | 44 +++ .../interfaces/acl/common/Ip4AclTranslator.java | 149 ++++++++++ .../interfaces/acl/common/Ip6AclTranslator.java | 182 ++++++++++++ .../interfaces/acl/common/L2AclTranslator.java | 90 ++++++ .../v3po/interfaces/acl/common/PortPair.java | 126 ++++++++ .../interfaces/acl/egress/EgressIetfAclWriter.java | 98 +++++++ .../interfaces/acl/egress/IetfAclCustomizer.java | 38 ++- .../acl/egress/SubInterfaceIetfAclCustomizer.java | 51 +++- .../v3po/interfaces/acl/ingress/AceEthWriter.java | 85 ------ .../v3po/interfaces/acl/ingress/AceIp4Writer.java | 94 ------ .../v3po/interfaces/acl/ingress/AceIp6Writer.java | 99 ------- .../interfaces/acl/ingress/AceIpAndEthWriter.java | 129 --------- .../v3po/interfaces/acl/ingress/AceWriter.java | 54 ---- .../v3po/interfaces/acl/ingress/AclTranslator.java | 74 ----- .../interfaces/acl/ingress/IetfAclCustomizer.java | 6 +- .../v3po/interfaces/acl/ingress/IetfAclWriter.java | 316 --------------------- .../acl/ingress/IngressIetfAclWriter.java | 109 +++++++ .../interfaces/acl/ingress/Ip4AclTranslator.java | 149 ---------- .../interfaces/acl/ingress/Ip6AclTranslator.java | 182 ------------ .../interfaces/acl/ingress/L2AclTranslator.java | 90 ------ .../v3po/interfaces/acl/ingress/PortPair.java | 126 -------- .../acl/ingress/SubInterfaceIetfAclCustomizer.java | 17 +- .../interfaces/acl/common/AceEthWriterTest.java | 94 ++++++ .../interfaces/acl/common/AceIp4WriterTest.java | 189 ++++++++++++ .../interfaces/acl/common/AceIp6WriterTest.java | 201 +++++++++++++ .../acl/common/AceIpAndEthWriterTest.java | 123 ++++++++ .../acl/common/AceIpWriterTestUtils.java | 34 +++ .../v3po/interfaces/acl/common/PortPairTest.java | 114 ++++++++ .../interfaces/acl/ingress/AceEthWriterTest.java | 94 ------ .../interfaces/acl/ingress/AceIp4WriterTest.java | 188 ------------ .../interfaces/acl/ingress/AceIp6WriterTest.java | 201 ------------- .../acl/ingress/AceIpAndEthWriterTest.java | 123 -------- .../acl/ingress/AceIpWriterTestUtils.java | 34 --- .../acl/ingress/IetfAclCustomizerTest.java | 2 +- .../v3po/interfaces/acl/ingress/PortPairTest.java | 114 -------- .../ingress/SubInterfaceIetfAclCustomizerTest.java | 2 +- 49 files changed, 2528 insertions(+), 2241 deletions(-) create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/EgressIetfAClWriterProvider.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IetfAClWriterProvider.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IngressIetfAClWriterProvider.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AbstractIetfAclWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4Writer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6Writer.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AclTranslator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/IetfAclWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip4AclTranslator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip6AclTranslator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/L2AclTranslator.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPair.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/EgressIetfAclWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4Writer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6Writer.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AclTranslator.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclWriter.java create mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip4AclTranslator.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip6AclTranslator.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/L2AclTranslator.java delete mode 100644 v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPair.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriterTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4WriterTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6WriterTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriterTest.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpWriterTestUtils.java create mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPairTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java delete mode 100644 v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java (limited to 'v3po') diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/EgressIetfAClWriterProvider.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/EgressIetfAClWriterProvider.java new file mode 100644 index 000000000..e2b60e9f4 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/EgressIetfAClWriterProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import io.fd.honeycomb.translate.v3po.interfaces.acl.egress.EgressIetfAclWriter; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; + +class EgressIetfAClWriterProvider implements Provider { + + private final FutureJVppCore jvpp; + + @Inject + public EgressIetfAClWriterProvider(final FutureJVppCore jvpp) { + this.jvpp = jvpp; + } + + @Override + public EgressIetfAclWriter get() { + return new EgressIetfAclWriter(jvpp); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IetfAClWriterProvider.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IetfAClWriterProvider.java deleted file mode 100644 index 301c30501..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IetfAClWriterProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po; - -import com.google.inject.Inject; -import com.google.inject.Provider; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter; -import io.fd.vpp.jvpp.core.future.FutureJVppCore; - -class IetfAClWriterProvider implements Provider { - - private final FutureJVppCore jvpp; - - @Inject - public IetfAClWriterProvider(final FutureJVppCore jvpp) { - this.jvpp = jvpp; - } - - @Override - public IetfAclWriter get() { - return new IetfAclWriter(jvpp); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IngressIetfAClWriterProvider.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IngressIetfAClWriterProvider.java new file mode 100644 index 000000000..c4e966460 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IngressIetfAClWriterProvider.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IngressIetfAclWriter; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; + +class IngressIetfAClWriterProvider implements Provider { + + private final FutureJVppCore jvpp; + + @Inject + public IngressIetfAClWriterProvider(final FutureJVppCore jvpp) { + this.jvpp = jvpp; + } + + @Override + public IngressIetfAclWriter get() { + return new IngressIetfAclWriter(jvpp); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java index be3801bd2..63593afd5 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java @@ -34,9 +34,10 @@ import io.fd.honeycomb.translate.v3po.interfaces.TapCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.VhostUserCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.VxlanCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.VxlanGpeCustomizer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.AclCustomizer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter; import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.acl.egress.EgressIetfAclWriter; +import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.AclCustomizer; +import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IngressIetfAclWriter; import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4AddressCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4Customizer; import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4NeighbourCustomizer; @@ -56,10 +57,6 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev14061 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Neighbor; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.VppInterfaceAugmentation; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Ethernet; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Gre; @@ -72,6 +69,10 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.Vxlan; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.VxlanGpe; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.acl.Ingress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.L2Acl; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.PbbRewriteInterfaceAugmentation; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.pbb.rev161214.interfaces._interface.PbbRewrite; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -94,7 +95,8 @@ public final class InterfacesWriterFactory implements WriterFactory { org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Egress.class); private final FutureJVppCore jvpp; - private final IetfAclWriter aclWriter; + private final IngressIetfAclWriter ingressAclWriter; + private final EgressIetfAclWriter egressAclWriter; private final NamingContext bdNamingContext; private final NamingContext ifcNamingContext; private final VppClassifierContextManager classifyTableContext; @@ -102,13 +104,15 @@ public final class InterfacesWriterFactory implements WriterFactory { @Inject public InterfacesWriterFactory(final FutureJVppCore vppJvppIfcDependency, - final IetfAclWriter aclWriter, + final IngressIetfAclWriter ingressAclWriter, + final EgressIetfAclWriter egressAclWriter, @Named("bridge-domain-context") final NamingContext bridgeDomainContextDependency, @Named("interface-context") final NamingContext interfaceContextDependency, @Named("classify-table-context") final VppClassifierContextManager classifyTableContext, final DisabledInterfacesManager ifcDisableContext) { this.jvpp = vppJvppIfcDependency; - this.aclWriter = aclWriter; + this.ingressAclWriter = ingressAclWriter; + this.egressAclWriter = egressAclWriter; this.bdNamingContext = bridgeDomainContextDependency; this.ifcNamingContext = interfaceContextDependency; this.ifcDisableContext = ifcDisableContext; @@ -125,7 +129,7 @@ public final class InterfacesWriterFactory implements WriterFactory { // Interface1 (ietf-ip augmentation) addInterface1AugmentationWriters(IFC_ID, registry); // SubinterfaceAugmentation - new SubinterfaceAugmentationWriterFactory(jvpp, aclWriter, ifcNamingContext, bdNamingContext, + new SubinterfaceAugmentationWriterFactory(jvpp, ingressAclWriter, egressAclWriter, ifcNamingContext, bdNamingContext, classifyTableContext).init(registry); addPbbAugmentationWriters(IFC_ID, registry); @@ -210,7 +214,7 @@ public final class InterfacesWriterFactory implements WriterFactory { org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class); registry.subtreeAdd( Sets.newHashSet(accessListsIdIngress, aclIdIngress), - new GenericWriter<>(INGRESS_IETF_ACL_ID, new IetfAclCustomizer(aclWriter, ifcNamingContext))); + new GenericWriter<>(INGRESS_IETF_ACL_ID, new IetfAclCustomizer(ingressAclWriter, ifcNamingContext))); // Ingress IETF-ACL, also handles AccessLists and Acl: final InstanceIdentifier accessListsIdEgress = InstanceIdentifier.create( @@ -221,7 +225,7 @@ public final class InterfacesWriterFactory implements WriterFactory { registry.subtreeAdd( Sets.newHashSet(accessListsIdEgress, aclIdEgress), new GenericWriter<>(EGRESS_IETF_ACL_ID, - new io.fd.honeycomb.translate.v3po.interfaces.acl.egress.IetfAclCustomizer(aclWriter, + new io.fd.honeycomb.translate.v3po.interfaces.acl.egress.IetfAclCustomizer(egressAclWriter, ifcNamingContext))); } diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/SubinterfaceAugmentationWriterFactory.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/SubinterfaceAugmentationWriterFactory.java index afa362d5c..1ef8b3865 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/SubinterfaceAugmentationWriterFactory.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/SubinterfaceAugmentationWriterFactory.java @@ -23,16 +23,18 @@ import com.google.common.collect.Sets; import io.fd.honeycomb.translate.impl.write.GenericListWriter; import io.fd.honeycomb.translate.impl.write.GenericWriter; import io.fd.honeycomb.translate.v3po.interfaces.RewriteCustomizer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.SubInterfaceAclCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.SubInterfaceCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.SubInterfaceL2Customizer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter; +import io.fd.honeycomb.translate.v3po.interfaces.acl.egress.EgressIetfAclWriter; +import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IngressIetfAclWriter; +import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.SubInterfaceAclCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.SubInterfaceIetfAclCustomizer; import io.fd.honeycomb.translate.v3po.interfaces.ip.SubInterfaceIpv4AddressCustomizer; -import io.fd.honeycomb.translate.vpp.util.NamingContext; import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager; +import io.fd.honeycomb.translate.vpp.util.NamingContext; import io.fd.honeycomb.translate.write.WriterFactory; import io.fd.honeycomb.translate.write.registry.ModifiableWriterRegistryBuilder; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; import org.opendaylight.yang.gen.v1.urn.ieee.params.xml.ns.yang.dot1q.types.rev150626.dot1q.tag.or.any.Dot1qTag; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip4Acl; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.acl.base.attributes.Ip6Acl; @@ -54,12 +56,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.ip4.attributes.ipv4.Address; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.tag.rewrite.PushTags; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import io.fd.vpp.jvpp.core.future.FutureJVppCore; public final class SubinterfaceAugmentationWriterFactory implements WriterFactory { private final FutureJVppCore jvpp; - private final IetfAclWriter aclWriter; + private final IngressIetfAclWriter ingressAclWriter; + private final EgressIetfAclWriter egressAclWriter; private final NamingContext ifcContext; private final NamingContext bdContext; private final VppClassifierContextManager classifyTableContext; @@ -79,10 +81,12 @@ public final class SubinterfaceAugmentationWriterFactory implements WriterFactor org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Egress.class); public SubinterfaceAugmentationWriterFactory(final FutureJVppCore jvpp, - final IetfAclWriter aclWriter, + final IngressIetfAclWriter ingressAclWriter, + final EgressIetfAclWriter egressAclWriter, final NamingContext ifcContext, final NamingContext bdContext, final VppClassifierContextManager classifyTableContext) { this.jvpp = jvpp; - this.aclWriter = aclWriter; + this.ingressAclWriter = ingressAclWriter; + this.egressAclWriter = egressAclWriter; this.ifcContext = ifcContext; this.bdContext = bdContext; this.classifyTableContext = classifyTableContext; @@ -138,7 +142,7 @@ public final class SubinterfaceAugmentationWriterFactory implements WriterFactor org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class); registry.subtreeAdd( Sets.newHashSet(accessListsIdIngress, aclIdIngress), - new GenericWriter<>(SUBIF_INGRESS_IETF_ACL_ID, new SubInterfaceIetfAclCustomizer(aclWriter, ifcContext))); + new GenericWriter<>(SUBIF_INGRESS_IETF_ACL_ID, new SubInterfaceIetfAclCustomizer(ingressAclWriter, ifcContext))); // Egress IETF-ACL, also handles AccessLists and Acl: final InstanceIdentifier accessListsIdEgress = InstanceIdentifier.create( @@ -148,6 +152,7 @@ public final class SubinterfaceAugmentationWriterFactory implements WriterFactor org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl.class); registry.subtreeAdd( Sets.newHashSet(accessListsIdEgress, aclIdEgress), - new GenericWriter<>(SUBIF_EGRESS_IETF_ACL_ID, new io.fd.honeycomb.translate.v3po.interfaces.acl.egress.SubInterfaceIetfAclCustomizer(aclWriter, ifcContext))); + new GenericWriter<>(SUBIF_EGRESS_IETF_ACL_ID, new io.fd.honeycomb.translate.v3po.interfaces.acl.egress.SubInterfaceIetfAclCustomizer( + egressAclWriter, ifcContext))); } } diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java index e30f9e6e8..e2f9c6db7 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java @@ -26,11 +26,12 @@ import io.fd.honeycomb.translate.v3po.cfgattrs.V3poConfiguration; import io.fd.honeycomb.translate.v3po.initializers.InterfacesInitializer; import io.fd.honeycomb.translate.v3po.initializers.VppClassifierInitializer; import io.fd.honeycomb.translate.v3po.initializers.VppInitializer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter; +import io.fd.honeycomb.translate.v3po.interfaces.acl.egress.EgressIetfAclWriter; +import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IngressIetfAclWriter; import io.fd.honeycomb.translate.v3po.notification.InterfaceChangeNotificationProducer; -import io.fd.honeycomb.translate.vpp.util.NamingContext; import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager; import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManagerImpl; +import io.fd.honeycomb.translate.vpp.util.NamingContext; import io.fd.honeycomb.translate.write.WriterFactory; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -64,7 +65,8 @@ public class V3poModule extends AbstractModule { bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(1)); // Utils - bind(IetfAclWriter.class).toProvider(IetfAClWriterProvider.class); + bind(IngressIetfAclWriter.class).toProvider(IngressIetfAClWriterProvider.class); + bind(EgressIetfAclWriter.class).toProvider(EgressIetfAClWriterProvider.class); // Context utility for deleted interfaces bind(DisabledInterfacesManager.class).toInstance(new DisabledInterfacesManager()); diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AbstractIetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AbstractIetfAclWriter.java new file mode 100644 index 000000000..1a1fbd519 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AbstractIetfAclWriter.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.HashMap; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.CompletionStage; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.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.matches.AceType; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.AceIpVersion; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +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.AceIpAndEth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractIetfAclWriter implements IetfAclWriter, JvppReplyConsumer, AclTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractIetfAclWriter.class); + private static final int NOT_DEFINED = -1; + protected final FutureJVppCore jvpp; + + private Map> aceWriters = new HashMap<>(); + + public AbstractIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) { + this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null"); + aceWriters.put(AclType.ETH, new AceEthWriter()); + aceWriters.put(AclType.IP4, new AceIp4Writer()); + aceWriters.put(AclType.IP6, new AceIp6Writer()); + aceWriters.put(AclType.ETH_AND_IP, new AceIpAndEthWriter()); + } + + private static Stream aclToAceStream(@Nonnull final Acl assignedAcl, + @Nonnull final WriteContext writeContext) { + final String aclName = assignedAcl.getName(); + final Class aclType = assignedAcl.getType(); + + // ietf-acl updates are handled first, so we use writeContext.readAfter + final Optional + aclOptional = + writeContext.readAfter(io.fd.honeycomb.translate.v3po.interfaces.acl.IetfAclWriter.ACL_ID.child( + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class, + new AclKey(aclName, aclType))); + checkArgument(aclOptional.isPresent(), "Acl lists not configured"); + final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl + acl = aclOptional.get(); + + final AccessListEntries accessListEntries = acl.getAccessListEntries(); + checkArgument(accessListEntries != null, "access list entries not configured"); + + return accessListEntries.getAce().stream(); + } + + protected void removeClassifyTable(@Nonnull final InstanceIdentifier id, final int tableIndex) + throws WriteFailedException { + + if (tableIndex == -1) { + return; // classify table id is absent + } + final ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.tableIndex = tableIndex; + final CompletionStage cs = jvpp.classifyAddDelTable(request); + getReplyForDelete(cs.toCompletableFuture(), id); + } + + protected static boolean appliesToIp4Path(final Ace ace) { + final AceType aceType = ace.getMatches().getAceType(); + final AclType aclType = AclType.fromAce(ace); + if (aclType == AclType.IP4) { + return true; + } + if (aclType == AclType.ETH) { + return true; // L2 only rules are possible for IP4 traffic + } + if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType) + .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv4) { + return true; + } + return false; + } + + protected static boolean appliesToIp6Path(final Ace ace) { + final AceType aceType = ace.getMatches().getAceType(); + final AclType aclType = AclType.fromAce(ace); + if (aclType == AclType.IP6) { + return true; + } + if (aclType == AclType.ETH) { + return true; // L2 only rules are possible for IP6 traffic + } + if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType) + .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv6) { + return true; + } + return false; + } + + protected static List getACEs(@Nonnull final List acls, @Nonnull final WriteContext writeContext, + final Predicate filter) { + return acls.stream().flatMap(acl -> aclToAceStream(acl, writeContext)).filter(filter) + .collect(Collectors.toList()); + } + + protected int writeAces(final InstanceIdentifier id, final List aces, + final AccessLists.DefaultAction defaultAction, final InterfaceMode mode, + final int vlanTags) throws WriteFailedException { + if (aces.isEmpty()) { + return NOT_DEFINED; + } + + int nextTableIndex = configureDefaultAction(id, defaultAction); + final ListIterator iterator = aces.listIterator(aces.size()); + while (iterator.hasPrevious()) { + final Ace ace = iterator.previous(); + LOG.trace("Processing ACE: {}", ace); + + final AceWriter aceWriter = + aceWriters.get(AclType.fromAce(ace)); + if (aceWriter == null) { + LOG.warn("AceProcessor for {} not registered. Skipping ACE.", ace.getClass()); + } else { + final AceType aceType = ace.getMatches().getAceType(); + final PacketHandling action = ace.getActions().getPacketHandling(); + final ClassifyAddDelTable ctRequest = aceWriter.createTable(aceType, mode, nextTableIndex, vlanTags); + nextTableIndex = createClassifyTable(id, ctRequest); + final List sessionRequests = + aceWriter.createSession(action, aceType, mode, nextTableIndex, vlanTags); + for (ClassifyAddDelSession csRequest : sessionRequests) { + createClassifySession(id, csRequest); + } + } + } + return nextTableIndex; + } + + private int configureDefaultAction(@Nonnull final InstanceIdentifier id, + final AccessLists.DefaultAction defaultAction) + throws WriteFailedException { + ClassifyAddDelTable ctRequest = createTable(-1); + if (AccessLists.DefaultAction.Permit.equals(defaultAction)) { + ctRequest.missNextIndex = -1; + } else { + ctRequest.missNextIndex = 0; + } + ctRequest.mask = new byte[16]; + ctRequest.skipNVectors = 0; + ctRequest.matchNVectors = 1; + return createClassifyTable(id, ctRequest); + } + + private int createClassifyTable(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyAddDelTable request) + throws WriteFailedException { + final CompletionStage cs = jvpp.classifyAddDelTable(request); + + final ClassifyAddDelTableReply reply = getReplyForWrite(cs.toCompletableFuture(), id); + return reply.newTableIndex; + } + + private void createClassifySession(@Nonnull final InstanceIdentifier id, + @Nonnull final ClassifyAddDelSession request) + throws WriteFailedException { + final CompletionStage cs = jvpp.classifyAddDelSession(request); + + getReplyForWrite(cs.toCompletableFuture(), id); + } + + private enum AclType { + ETH, IP4, IP6, ETH_AND_IP; + + @Nonnull + private static AclType fromAce(final Ace ace) { + AclType result = null; + final AceType aceType; + try { + aceType = ace.getMatches().getAceType(); + if (aceType instanceof AceEth) { + result = ETH; + } else if (aceType instanceof AceIp) { + final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion(); + if (aceIpVersion == null) { + throw new IllegalArgumentException("Incomplete ACE (ip-version was not provided): " + ace); + } + if (aceIpVersion instanceof AceIpv4) { + result = IP4; + } else if (aceIpVersion instanceof AceIpv6) { + result = IP6; + } + } else if (aceType instanceof AceIpAndEth) { + result = ETH_AND_IP; + } + } catch (NullPointerException e) { + throw new IllegalArgumentException("Incomplete ACE: " + ace, e); + } + if (result == null) { + throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType)); + } + return result; + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriter.java new file mode 100644 index 000000000..14124dcc7 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriter.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.honeycomb.translate.v3po.interfaces.acl.common; + +import com.google.common.annotations.VisibleForTesting; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.matches.ace.type.AceEth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class AceEthWriter implements AceWriter, AclTranslator, L2AclTranslator { + + @VisibleForTesting + static final int MATCH_N_VECTORS = 1; + private static final Logger LOG = LoggerFactory.getLogger(AceEthWriter.class); + + @Override + public ClassifyAddDelTable createTable(@Nonnull final AceEth aceEth, + @Nullable final InterfaceMode mode, + final int nextTableIndex, + final int vlanTags) { + final ClassifyAddDelTable request = createTable(nextTableIndex); + + request.mask = new byte[16]; + boolean aceIsEmpty = + destinationMacAddressMask(aceEth.getDestinationMacAddressMask(), aceEth.getDestinationMacAddress(), + request); + aceIsEmpty &= + sourceMacAddressMask(aceEth.getSourceMacAddressMask(), aceEth.getSourceMacAddress(), request); + + if (aceIsEmpty) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", aceEth.toString())); + } + + request.skipNVectors = 0; + request.matchNVectors = MATCH_N_VECTORS; + + LOG.debug("ACE rule={} translated to table={}.", aceEth, request); + return request; + } + + @Override + public List createSession(@Nonnull final PacketHandling action, + @Nonnull final AceEth aceEth, + @Nullable final InterfaceMode mode, + final int tableIndex, + final int vlanTags) { + final ClassifyAddDelSession request = createSession(action, tableIndex); + + request.match = new byte[16]; + boolean noMatch = destinationMacAddressMatch(aceEth.getDestinationMacAddress(), request); + noMatch &= sourceMacAddressMatch(aceEth.getSourceMacAddress(), request); + + if (noMatch) { + throw new IllegalArgumentException( + String.format("Ace %s does not define neither source nor destination MAC address", + aceEth.toString())); + } + + LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceEth, request); + return Collections.singletonList(request); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4Writer.java new file mode 100644 index 000000000..7d75e3969 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4Writer.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.honeycomb.translate.v3po.interfaces.acl.common; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.annotations.VisibleForTesting; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.matches.ace.type.AceIp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class AceIp4Writer implements AceWriter, AclTranslator, Ip4AclTranslator { + + @VisibleForTesting + static final int MATCH_N_VECTORS = 3; // number of 16B vectors + private static final int TABLE_MASK_LENGTH = 48; + private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class); + + @Override + public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp, + @Nullable final InterfaceMode mode, + final int nextTableIndex, + final int vlanTags) { + checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp); + final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion(); + + final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size(); + final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions); + request.skipNVectors = 0; // match entire L2 and L3 header + request.matchNVectors = MATCH_N_VECTORS; + request.mask = new byte[TABLE_MASK_LENGTH]; + + final int baseOffset = getVlanTagsLen(vlanTags); + boolean aceIsEmpty = ip4Mask(baseOffset, mode, aceIp, ipVersion, request); + if (aceIsEmpty) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", aceIp.toString())); + } + + LOG.debug("ACE rule={} translated to table={}.", aceIp, request); + return request; + } + + @Override + public List createSession(@Nonnull final PacketHandling action, + @Nonnull final AceIp aceIp, + @Nullable final InterfaceMode mode, + final int tableIndex, + final int vlanTags) { + checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp); + final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion(); + + final List portPairs = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()); + final List requests = new ArrayList<>(portPairs.size()); + for (final PortPair pair : portPairs) { + final ClassifyAddDelSession request = createSession(action, tableIndex); + request.match = new byte[TABLE_MASK_LENGTH]; + + final int baseOffset = getVlanTagsLen(vlanTags); + boolean noMatch = ip4Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request); + if (noMatch) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", aceIp.toString())); + } + + LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request); + requests.add(request); + } + return requests; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6Writer.java new file mode 100644 index 000000000..cad80022e --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6Writer.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.matches.ace.type.AceIp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +final class AceIp6Writer implements AceWriter, AclTranslator, Ip6AclTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(AceIp6Writer.class); + + @Override + public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp, + @Nullable final InterfaceMode mode, + final int nextTableIndex, + final int vlanTags) { + checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp); + final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion(); + + final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size(); + final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions); + request.skipNVectors = 0; // match entire L2 and L3 header + request.mask = new byte[getTableMaskLength(vlanTags)]; + request.matchNVectors = request.mask.length/16; + + final int baseOffset = getVlanTagsLen(vlanTags); + boolean aceIsEmpty = ip6Mask(baseOffset, mode, aceIp, ipVersion, request); + if (aceIsEmpty) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", aceIp.toString())); + } + + LOG.debug("ACE rule={} translated to table={}.", aceIp, request); + return request; + } + + private static int getTableMaskLength(final int vlanTags) { + if (vlanTags == 2) { + return 80; + } else { + return 64; + } + } + + @Override + public List createSession(@Nonnull final PacketHandling action, + @Nonnull final AceIp aceIp, + @Nullable final InterfaceMode mode, + final int tableIndex, + final int vlanTags) { + checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp); + final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion(); + final List portPairs = + PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()); + + final List requests = new ArrayList<>(portPairs.size()); + for (final PortPair pair : portPairs) { + final ClassifyAddDelSession request = createSession(action, tableIndex); + request.match = new byte[getTableMaskLength(vlanTags)]; + + final int baseOffset = getVlanTagsLen(vlanTags); + boolean noMatch = ip6Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request); + if (noMatch) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", aceIp.toString())); + } + + LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request); + requests.add(request); + } + return requests; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriter.java new file mode 100644 index 000000000..ca12cbe19 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriter.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +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.AceIpAndEth; +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.ace.ip.and.eth.AceIpVersion; +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.ace.ip.and.eth.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.ace.ip.and.eth.ace.ip.version.AceIpv6; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class AceIpAndEthWriter + implements AceWriter, AclTranslator, L2AclTranslator, Ip4AclTranslator, Ip6AclTranslator { + + private static final Logger LOG = LoggerFactory.getLogger(AceIpAndEthWriter.class); + + private static int maskLength(@Nonnull final AceIpAndEth ace, final int vlanTags) { + if (ace.getAceIpVersion() != null) { + if (ace.getAceIpVersion() instanceof AceIpv4) { + return 48; + } else { + return vlanTags == 2 + ? 80 + : 64; + } + } + return 16; + } + + @Override + public ClassifyAddDelTable createTable(@Nonnull final AceIpAndEth ace, @Nullable final InterfaceMode mode, + final int nextTableIndex, final int vlanTags) { + final int numberOfSessions = PortPair.fromRange(ace.getSourcePortRange(), ace.getDestinationPortRange()).size(); + final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions); + final int maskLength = maskLength(ace, vlanTags); + request.mask = new byte[maskLength]; + request.skipNVectors = 0; + request.matchNVectors = maskLength / 16; + + boolean aceIsEmpty = + destinationMacAddressMask(ace.getDestinationMacAddressMask(), ace.getDestinationMacAddress(), request); + aceIsEmpty &= sourceMacAddressMask(ace.getSourceMacAddressMask(), ace.getSourceMacAddress(), request); + + // if we use classifier API, we need to know ip version (fields common for ip4 and ip6 have different offsets): + final AceIpVersion aceIpVersion = ace.getAceIpVersion(); + checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion"); + + final int baseOffset = getVlanTagsLen(vlanTags); + if (aceIpVersion instanceof AceIpv4) { + final AceIpv4 ipVersion = (AceIpv4) aceIpVersion; + aceIsEmpty &= ip4Mask(baseOffset, mode, ace, ipVersion, request); + } else if (aceIpVersion instanceof AceIpv6) { + final AceIpv6 ipVersion = (AceIpv6) aceIpVersion; + aceIsEmpty &= ip6Mask(baseOffset, mode, ace, ipVersion, request); + } else { + throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion)); + } + + if (aceIsEmpty) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", ace.toString())); + } + + LOG.debug("ACE rule={} translated to table={}.", ace, request); + return request; + } + + @Override + public List createSession(@Nonnull final PacketHandling action, + @Nonnull final AceIpAndEth ace, + @Nullable final InterfaceMode mode, final int tableIndex, + final int vlanTags) { + final List portPairs = PortPair.fromRange(ace.getSourcePortRange(), ace.getDestinationPortRange()); + final List requests = new ArrayList<>(portPairs.size()); + for (final PortPair pair : portPairs) { + final ClassifyAddDelSession request = createSession(action, tableIndex); + request.match = new byte[maskLength(ace, vlanTags)]; + + boolean noMatch = destinationMacAddressMatch(ace.getDestinationMacAddress(), request); + noMatch &= sourceMacAddressMatch(ace.getSourceMacAddress(), request); + + final AceIpVersion aceIpVersion = ace.getAceIpVersion(); + checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion"); + + final int baseOffset = getVlanTagsLen(vlanTags); + if (aceIpVersion instanceof AceIpv4) { + final AceIpv4 ipVersion = (AceIpv4) aceIpVersion; + noMatch &= ip4Match(baseOffset, mode, ace, ipVersion, pair.getSrc(), pair.getDst(), request); + } else if (aceIpVersion instanceof AceIpv6) { + final AceIpv6 ipVersion = (AceIpv6) aceIpVersion; + noMatch &= ip6Match(baseOffset, mode, ace, ipVersion, pair.getSrc(), pair.getDst(), request); + } else { + throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion)); + } + + if (noMatch) { + throw new IllegalArgumentException( + String.format("Ace %s does not define packet field match values", ace.toString())); + } + LOG.debug("ACE action={}, rule={} translated to session={}.", action, ace, request); + requests.add(request); + } + return requests; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceWriter.java new file mode 100644 index 000000000..ae540f94d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceWriter.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.util.List; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.matches.AceType; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; + +/** + * Writer responsible for translation of ietf-acl model ACEs to VPP's classify tables and sessions. + * + * @param type of access control list entry + */ +interface AceWriter { + /** + * @param ace access list entry + * @param mode interface mode (L2/L3) + * @param nextTableIndex index of the next classify table in chain + * @param vlanTags number of vlan tags + */ + @Nonnull + ClassifyAddDelTable createTable(@Nonnull final T ace, @Nullable final InterfaceMode mode, final int nextTableIndex, + final int vlanTags); + + /** + * @param action to be taken when packet does match the specified ace + * @param ace access list entry + * @param mode interface mode (L2/L3) + * @param tableIndex index of corresponding classify table + * @param vlanTags number of vlan tags + */ + @Nonnull + List createSession(@Nonnull final PacketHandling action, @Nonnull T ace, + @Nullable final InterfaceMode mode, final int tableIndex, final int vlanTags); +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AclTranslator.java new file mode 100644 index 000000000..2d898f1d9 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AclTranslator.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import javax.annotation.Nonnegative; +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.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.Permit; + +/** + * Utility that helps translating of ietf-acl model ACEs to VPP's classify tables and sessions. + */ +interface AclTranslator { + int TABLE_MEM_SIZE = 8 * 1024; + int VLAN_TAG_LEN = 4; + + default ClassifyAddDelTable createTable(final int nextTableIndex) { + return createTable(nextTableIndex, 1); + } + + default ClassifyAddDelTable createTable(final int nextTableIndex, @Nonnegative final int numberOfSessions) { + final ClassifyAddDelTable request = new ClassifyAddDelTable(); + request.isAdd = 1; + request.tableIndex = -1; // value not present + request.nbuckets = numberOfSessions; + request.nextTableIndex = nextTableIndex; + + + // TODO: HONEYCOMB-181 minimise memory used by classify tables (we create a lot of them to make ietf-acl model + // mapping more convenient): + // according to https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers#Creating_a_classifier_table, + // classify table needs 16*(1 + match_n_vectors) bytes, but this does not quite work, + // so setting 8K +1k*numberOfSessions for now + checkArgument(numberOfSessions>0, "negative numberOfSessions %s", numberOfSessions); + request.memorySize = TABLE_MEM_SIZE+1024*(numberOfSessions-1); + request.missNextIndex = -1; // value not set, but anyway it is ignored for tables in chain + return request; + } + + default ClassifyAddDelSession createSession(@Nonnull final PacketHandling action, final int tableIndex) { + final ClassifyAddDelSession request = new ClassifyAddDelSession(); + request.isAdd = 1; + request.tableIndex = tableIndex; + request.opaqueIndex = ~0; // value not used + + if (action instanceof Permit) { + request.hitNextIndex = -1; + } // deny (0) is default value + + return request; + } + + default int getVlanTagsLen(final int vlanTags) { + return vlanTags * VLAN_TAG_LEN; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/IetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/IetfAclWriter.java new file mode 100644 index 000000000..1ce5a040d --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/IetfAclWriter.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.honeycomb.translate.v3po.interfaces.acl.common; + +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import java.util.List; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface IetfAclWriter { + default void write(@Nonnull final InstanceIdentifier id, final int ifIndex, @Nonnull final List acls, + final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode, + @Nonnull final WriteContext writeContext) + throws WriteFailedException { + write(id, ifIndex, acls, defaultAction, mode, writeContext, 0); + } + + void write(@Nonnull final InstanceIdentifier id, int ifIndex, @Nonnull final List acls, + final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode, + @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags) + throws WriteFailedException; + + void deleteAcl(InstanceIdentifier id, int ifIndex) throws WriteFailedException; +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip4AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip4AclTranslator.java new file mode 100644 index 000000000..304d6c1f0 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip4AclTranslator.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import com.google.common.primitives.Ints; +import io.fd.honeycomb.translate.vpp.util.Ipv4Translator; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv4HeaderFields; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; + +interface Ip4AclTranslator extends Ipv4Translator { + int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6) + int DSCP_OFFSET = 15; + int DSCP_MASK = 0xfc; + + int IP_PROTOCOL_OFFSET = ETHER_TYPE_OFFSET + 11; + int IP_PROTOCOL_MASK = 0xff; + + int IP4_LEN = 4; + int IP4_MASK_BIT_LENGTH = 32; + int SRC_IP_OFFSET = ETHER_TYPE_OFFSET + 14; + int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN; + int SRC_PORT_OFFSET = DST_IP_OFFSET + IP4_LEN; + int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2; + + default boolean ip4Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, + final AclIpv4HeaderFields ip4, final ClassifyAddDelTable request) { + boolean aceIsEmpty = true; + if (InterfaceMode.L2.equals(mode)) { + // in L2 mode we need to match ether type + request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff; + request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff; + } + if (header.getDscp() != null) { + aceIsEmpty = false; + request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits + } + if (header.getProtocol() != null) { // Internet Protocol number + aceIsEmpty = false; + request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK; + } + if (header.getSourcePortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + aceIsEmpty = false; + request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff; + request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff; + } + if (header.getDestinationPortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + aceIsEmpty = false; + request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff; + request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff; + } + if (ip4.getSourceIpv4Network() != null) { + aceIsEmpty = false; + System.arraycopy(Impl.toByteMask(ip4.getSourceIpv4Network()), 0, request.mask, + baseOffset + SRC_IP_OFFSET, IP4_LEN); + } + if (ip4.getDestinationIpv4Network() != null) { + aceIsEmpty = false; + System.arraycopy(Impl.toByteMask(ip4.getDestinationIpv4Network()), 0, request.mask, + baseOffset + DST_IP_OFFSET, IP4_LEN); + } + return aceIsEmpty; + } + + default boolean ip4Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, + final AclIpv4HeaderFields ip4, final Integer srcPort, + final Integer dstPort, final ClassifyAddDelSession request) { + boolean noMatch = true; + if (InterfaceMode.L2.equals(mode)) { + // match IP4 etherType (0x0800) + request.match[baseOffset + ETHER_TYPE_OFFSET] = 0x08; + request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = 0x00; + } + if (header.getDscp() != null) { + noMatch = false; + request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (header.getDscp().getValue() << 2)); + } + if (header.getProtocol() != null) { // Internet Protocol number + noMatch = false; + request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol()); + } + if (srcPort != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + noMatch = false; + request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8); + request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort); + } + if (header.getDestinationPortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + noMatch = false; + request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8); + request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort); + } + if (ip4.getSourceIpv4Network() != null) { + noMatch = false; + System.arraycopy(Impl.toMatchValue(ip4.getSourceIpv4Network()), 0, request.match, + baseOffset + SRC_IP_OFFSET, IP4_LEN); + + } + if (ip4.getDestinationIpv4Network() != null) { + noMatch = false; + System.arraycopy(Impl.toMatchValue(ip4.getDestinationIpv4Network()), 0, request.match, + baseOffset + DST_IP_OFFSET, IP4_LEN); + + } + return noMatch; + } + + class Impl { + private static byte[] toByteMask(final int prefixLength) { + final long mask = ((1L << prefixLength) - 1) << (IP4_MASK_BIT_LENGTH - prefixLength); + return Ints.toByteArray((int) mask); + } + + private static byte[] toByteMask(final Ipv4Prefix ipv4Prefix) { + final int prefixLength = Byte.valueOf(ipv4Prefix.getValue().split("/")[1]); + return toByteMask(prefixLength); + } + + private static byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) { + final String[] split = ipv4Prefix.getValue().split("/"); + final byte[] addressBytes = Ipv4Translator.INSTANCE.ipv4AddressNoZoneToArray(split[0]); + final byte[] mask = Impl.toByteMask(Byte.valueOf(split[1])); + for (int i = 0; i < addressBytes.length; ++i) { + addressBytes[i] &= mask[i]; + } + return addressBytes; + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip6AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip6AclTranslator.java new file mode 100644 index 000000000..c0da75687 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/Ip6AclTranslator.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.BitSet; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields; +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.InterfaceMode; + +interface Ip6AclTranslator { + + int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6) + int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET + 2; + int DSCP_MASK1 = 0x0f; + int DSCP_MASK2 = 0xc0; + int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET + 6; + int IP_PROTOCOL_MASK = 0xff; + int IP6_LEN = 16; + int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8; + int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN; + int SRC_PORT_OFFSET = DST_IP_OFFSET + IP6_LEN; + int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2; + + default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, + final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request) { + boolean aceIsEmpty = true; + if (InterfaceMode.L2.equals(mode)) { + // in L2 mode we need to match ether type + request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff; + request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff; + } + if (header.getDscp() != null) { + aceIsEmpty = false; + // DCSP (bits 4-9 of IP6 header) + request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1; + request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2; + } + if (header.getProtocol() != null) { // Internet Protocol number + aceIsEmpty = false; + request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK; + } + if (ip6.getFlowLabel() != null) { + aceIsEmpty = false; + // bits 12-31 + request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) 0x0f; + request.mask[baseOffset + IP_VERSION_OFFSET + 2] = (byte) 0xff; + request.mask[baseOffset + IP_VERSION_OFFSET + 3] = (byte) 0xff; + } + if (header.getSourcePortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + aceIsEmpty = false; + request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff; + request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff; + } + if (header.getDestinationPortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + aceIsEmpty = false; + request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff; + request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff; + } + if (ip6.getSourceIpv6Network() != null) { + aceIsEmpty = false; + final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network()); + System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length); + } + if (ip6.getDestinationIpv6Network() != null) { + aceIsEmpty = false; + final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network()); + System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length); + } + return aceIsEmpty; + } + + default boolean ip6Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, + final AclIpv6HeaderFields ip6, final Integer srcPort, final Integer dstPort, final ClassifyAddDelSession request) { + boolean noMatch = true; + if (InterfaceMode.L2.equals(mode)) { + // match IP6 etherType (0x86dd) + request.match[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0x86; + request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xdd; + } + if (header.getDscp() != null) { + noMatch = false; + final int dcsp = header.getDscp().getValue(); + // set bits 4-9 of IP6 header: + request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dcsp >> 2)); + request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dcsp << 6)); + } + if (header.getProtocol() != null) { // Internet Protocol number + noMatch = false; + request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol()); + } + if (ip6.getFlowLabel() != null) { + noMatch = false; + final int flowLabel = ip6.getFlowLabel().getValue().intValue(); + // bits 12-31 + request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16)); + request.match[baseOffset + IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8)); + request.match[baseOffset + IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel); + } + if (header.getSourcePortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + noMatch = false; + request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8); + request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort); + } + if (header.getDestinationPortRange() != null) { + // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present + noMatch = false; + request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8); + request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort); + } + if (ip6.getSourceIpv6Network() != null) { + noMatch = false; + final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network()); + System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN); + } + if (ip6.getDestinationIpv6Network() != null) { + noMatch = false; + final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network()); + System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN); + } + return noMatch; + } + + class Impl { + private static final int IP6_MASK_BIT_LENGTH = 128; + + private static byte[] toByteMask(final int prefixLength) { + final BitSet mask = new BitSet(IP6_MASK_BIT_LENGTH); + mask.set(0, prefixLength, true); + if (prefixLength < IP6_MASK_BIT_LENGTH) { + mask.set(prefixLength, IP6_MASK_BIT_LENGTH, false); + } + return mask.toByteArray(); + } + + private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) { + final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]); + return toByteMask(prefixLength); + } + + private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) { + final String[] split = ipv6Prefix.getValue().split("/"); + final byte[] addressBytes; + try { + addressBytes = InetAddress.getByName(split[0]).getAddress(); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Invalid IP6 address", e); + } + final byte[] mask = toByteMask(Short.valueOf(split[1])); + int pos = 0; + for (; pos < mask.length; ++pos) { + addressBytes[pos] &= mask[pos]; + } + // mask can be shorter that address, so we need to clear rest of the address: + for (; pos < addressBytes.length; ++pos) { + addressBytes[pos] = 0; + } + return addressBytes; + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/L2AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/L2AclTranslator.java new file mode 100644 index 000000000..c74db7e2a --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/L2AclTranslator.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import io.fd.honeycomb.translate.vpp.util.MacTranslator; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import java.util.List; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; + +interface L2AclTranslator extends MacTranslator { + + default boolean destinationMacAddressMask(final MacAddress dstMask, final MacAddress dstAddress, + final ClassifyAddDelTable request) { + // destination-mac-address or destination-mac-address-mask is present => + // ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00 + if (dstMask != null) { + final List parts = COLON_SPLITTER.splitToList(dstMask.getValue()); + int i = 0; + for (String part : parts) { + request.mask[i++] = parseHexByte(part); + } + return false; + } else if (dstAddress != null) { + for (int i = 0; i < 6; ++i) { + request.mask[i] = (byte) 0xff; + } + return false; + } + return true; + } + + default boolean sourceMacAddressMask(final MacAddress srcMask, final MacAddress srcAddress, + final ClassifyAddDelTable request) { + // source-mac-address or source-mac-address-mask => + // 00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00 + if (srcMask != null) { + final List parts = COLON_SPLITTER.splitToList(srcMask.getValue()); + int i = 6; + for (String part : parts) { + request.mask[i++] = parseHexByte(part); + } + return false; + } else if (srcAddress != null) { + for (int i = 6; i < 12; ++i) { + request.mask[i] = (byte) 0xff; + } + return false; + } + return true; + } + + default boolean destinationMacAddressMatch(final MacAddress dstAddress, final ClassifyAddDelSession request) { + if (dstAddress != null) { + final List parts = COLON_SPLITTER.splitToList(dstAddress.getValue()); + int i = 0; + for (String part : parts) { + request.match[i++] = parseHexByte(part); + } + return false; + } + return true; + } + + default boolean sourceMacAddressMatch(final MacAddress srcAddress, final ClassifyAddDelSession request) { + if (srcAddress != null) { + final List parts = COLON_SPLITTER.splitToList(srcAddress.getValue()); + int i = 6; + for (String part : parts) { + request.match[i++] = parseHexByte(part); + } + return false; + } + return true; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPair.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPair.java new file mode 100644 index 000000000..6d5d506d8 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPair.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiFunction; +import javax.annotation.Nullable; +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; + +/** + * Utility that produces cartesian product out of src and dst port ranges (used to translate ranges into + * list of classify sessions). + */ +final class PortPair { + private final Integer src; + private final Integer dst; + + PortPair(@Nullable final Integer src, @Nullable final Integer dst) { + this.src = src; + this.dst = dst; + } + + Integer getSrc() { + return src; + } + + Integer getDst() { + return dst; + } + + @Override + public String toString() { + return "(" + src + "," + dst + ")"; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + final PortPair that = (PortPair) o; + if (!Objects.equals(src, that.src)) { + return false; + } + if (!Objects.equals(dst, that.dst)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(src, dst); + } + + static List fromRange(final SourcePortRange srcRange, + final DestinationPortRange dstRange) { + final List result = new ArrayList<>(); + if (srcRange == null && dstRange == null) { + result.add(new PortPair(null, null)); + } else if (srcRange != null && dstRange == null) { + processSingleRange(result, srcRange.getLowerPort(), srcRange.getUpperPort(), PortPair::new); + } else if (srcRange == null && dstRange != null) { + processSingleRange(result, dstRange.getLowerPort(), dstRange.getUpperPort(), + (dst, src) -> new PortPair(src, dst)); + } else { + processDoubleRange(result, srcRange, dstRange); + } + return result; + } + + private static void processSingleRange(final List result, + final PortNumber lowerPort, + final PortNumber upperPort, + final BiFunction f) { + int low = lowerPort.getValue(); // mandatory + int hi = low; + if (upperPort != null) { + hi = upperPort.getValue(); + } + for (; low <= hi; ++low) { + result.add(f.apply(low, null)); + } + } + + private static void processDoubleRange(final List result, final SourcePortRange srcRange, + final DestinationPortRange dstRange) { + int srcL = srcRange.getLowerPort().getValue(); + int srcH = srcL; + if (srcRange.getUpperPort() != null) { + srcH = srcRange.getUpperPort().getValue(); + } + int dstL = dstRange.getLowerPort().getValue(); + int dstH = dstL; + if (dstRange.getUpperPort() != null) { + dstH = dstRange.getUpperPort().getValue(); + } + for (int i=srcL; i <= srcH; ++i) { + for (int j=dstL; j <= dstH; ++j) { + result.add(new PortPair(i, j)); + } + } + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/EgressIetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/EgressIetfAclWriter.java new file mode 100644 index 000000000..eee8f68eb --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/EgressIetfAclWriter.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.honeycomb.translate.v3po.interfaces.acl.egress; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.honeycomb.translate.v3po.interfaces.acl.common.AbstractIetfAclWriter; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.ClassifySetInterfaceL2Tables; +import io.fd.vpp.jvpp.core.dto.ClassifySetInterfaceL2TablesReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.ace.type.AceEth; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class EgressIetfAclWriter extends AbstractIetfAclWriter { + private static final int NOT_DEFINED = -1; + + public EgressIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) { + super(futureJVppCore); + } + + @Override + public void deleteAcl(@Nonnull final InstanceIdentifier id, final int swIfIndex) + throws WriteFailedException { + // We unassign and remove all ACL-related classify tables for given interface (we assume we are the only + // classify table manager) + unassignClassifyTables(id, swIfIndex); + + // TODO(HONEYCOMB-264): remove classify tables from vpp (we need to cache interface/acl mapping) + } + + private void unassignClassifyTables(@Nonnull final InstanceIdentifier id, final int swIfIndex) + throws WriteFailedException { + final ClassifySetInterfaceL2Tables request = new ClassifySetInterfaceL2Tables(); + request.swIfIndex = swIfIndex; + request.ip4TableIndex = NOT_DEFINED; + request.ip6TableIndex = NOT_DEFINED; + request.otherTableIndex = NOT_DEFINED; + request.isInput = 0; // egress + final CompletionStage cs = jvpp.classifySetInterfaceL2Tables(request); + getReplyForDelete(cs.toCompletableFuture(), id); + } + + @Override + public void write(@Nonnull final InstanceIdentifier id, int swIfIndex, @Nonnull final List acls, + final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode, + @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags) + throws WriteFailedException { + checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range"); + checkArgument(InterfaceMode.L2.equals(mode), "Writing egress Acls is supported only in L2 mode"); + + final ClassifySetInterfaceL2Tables request = new ClassifySetInterfaceL2Tables(); + request.isInput = 0; // egress + request.swIfIndex = swIfIndex; + + // applied to packets according to their ether type + final List ip4Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp4Path)); + request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags); + final List ip6Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp6Path)); + request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags); + final List aces = getACEs(acls, writeContext, EgressIetfAclWriter::isNotIpRule); + request.otherTableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags); + + final CompletionStage cs = jvpp.classifySetInterfaceL2Tables(request); + getReplyForWrite(cs.toCompletableFuture(), id); + } + + private static boolean isNotIpRule(final Ace ace) { + final Matches matches = ace.getMatches(); + checkArgument(matches != null, "Incomplete ACE: %s", ace); + return matches.getAceType() instanceof AceEth; + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/IetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/IetfAclCustomizer.java index 3dc9e2262..e8f8af296 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/IetfAclCustomizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/IetfAclCustomizer.java @@ -16,26 +16,28 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl.egress; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import io.fd.honeycomb.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter; import io.fd.honeycomb.translate.vpp.util.NamingContext; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; 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.v3po.rev161214.interfaces._interface.ietf.acl.Egress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class IetfAclCustomizer implements WriterCustomizer { private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class); - private final IetfAclWriter aclWriter; + private final EgressIetfAclWriter aclWriter; private final NamingContext interfaceContext; - - public IetfAclCustomizer(final IetfAclWriter aclWriter, final NamingContext interfaceContext) { + public IetfAclCustomizer(final EgressIetfAclWriter aclWriter, final NamingContext interfaceContext) { this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null"); this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); } @@ -43,20 +45,40 @@ public class IetfAclCustomizer implements WriterCustomizer { @Override public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Writing attributes for id={} dataAfter={}: NOT IMPLEMENTED YET", id, dataAfter); + final String ifName = id.firstKeyOf(Interface.class).getName(); + final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext()); + LOG.debug("Adding egress ACLs for interface={}(id={}): {}", ifName, ifIndex, dataAfter); + + final AccessLists accessLists = dataAfter.getAccessLists(); + checkArgument(accessLists != null && accessLists.getAcl() != null, + "ietf-acl container does not define acl list"); + + if (!InterfaceMode.L2.equals(accessLists.getMode())) { + LOG.debug("Writing egress Acls is supported only in L2 mode. Ignoring config: {}", dataAfter); + return; + } + + aclWriter.write(id, ifIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(), + writeContext); } @Override public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Egress dataBefore, @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Updating attributes for id={} dataBefore={} dataAfter={}: NOT IMPLEMENTED YET", id, dataBefore, dataAfter); - + LOG.debug("ACLs update: removing previously configured ACLs"); + deleteCurrentAttributes(id, dataBefore, writeContext); + LOG.debug("ACLs update: adding updated ACLs"); + writeCurrentAttributes(id, dataAfter, writeContext); + LOG.debug("ACLs update was successful"); } @Override public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Egress dataBefore, @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Deleting attributes for id={} dataBefore={}: NOT IMPLEMENTED YET", id, dataBefore); + final String ifName = id.firstKeyOf(Interface.class).getName(); + final int ifIndex = interfaceContext.getIndex(ifName, writeContext.getMappingContext()); + LOG.debug("Removing ACLs for interface={}(id={}): {}", ifName, ifIndex, dataBefore); + aclWriter.deleteAcl(id, ifIndex); } } diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java index b5198465a..cba045add 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java @@ -16,14 +16,23 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl.egress; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static io.fd.honeycomb.translate.vpp.util.SubInterfaceUtils.getNumberOfTags; +import com.google.common.base.Optional; import io.fd.honeycomb.translate.spi.write.WriterCustomizer; -import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter; import io.fd.honeycomb.translate.vpp.util.NamingContext; +import io.fd.honeycomb.translate.vpp.util.SubInterfaceUtils; import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; 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.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterface; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.interfaces._interface.sub.interfaces.SubInterfaceKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev161214.sub._interface.base.attributes.ietf.acl.Egress; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; @@ -31,31 +40,59 @@ import org.slf4j.LoggerFactory; public class SubInterfaceIetfAclCustomizer implements WriterCustomizer { private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class); - private final IetfAclWriter aclWriter; + private final EgressIetfAclWriter aclWriter; private final NamingContext interfaceContext; - public SubInterfaceIetfAclCustomizer(final IetfAclWriter aclWriter, final NamingContext interfaceContext) { + public SubInterfaceIetfAclCustomizer(final EgressIetfAclWriter aclWriter, final NamingContext interfaceContext) { this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null"); this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); } + private String getSubInterfaceName(@Nonnull final InstanceIdentifier id) { + final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); + final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); + return SubInterfaceUtils + .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + } + @Override public void writeCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Writing attributes for id={} dataAfter={}: NOT IMPLEMENTED YET", id, dataAfter); + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + LOG.debug("Adding IETF-ACL for sub-interface: {}(id={}): {}", subInterfaceName, subInterfaceIndex, dataAfter); + + final AccessLists accessLists = dataAfter.getAccessLists(); + checkArgument(accessLists != null && accessLists.getAcl() != null, + "ietf-acl container does not define acl list"); + + final Optional subInterfaceOptional = + writeContext.readAfter(id.firstIdentifierOf(SubInterface.class)); + checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id); + final SubInterface subInterface = subInterfaceOptional.get(); + + aclWriter + .write(id, subInterfaceIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(), + writeContext, getNumberOfTags(subInterface.getTags())); } @Override public void updateCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Egress dataBefore, @Nonnull final Egress dataAfter, @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Updating attributes for id={} dataBefore={} dataAfter={}: NOT IMPLEMENTED YET", id, dataBefore, dataAfter); - + LOG.debug("Sub-interface ACLs update: removing previously configured ACLs"); + deleteCurrentAttributes(id, dataBefore, writeContext); + LOG.debug("Sub-interface ACLs update: adding updated ACLs"); + writeCurrentAttributes(id, dataAfter, writeContext); + LOG.debug("Sub-interface ACLs update was successful"); } @Override public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Egress dataBefore, @Nonnull final WriteContext writeContext) throws WriteFailedException { - LOG.debug("Deleting attributes for id={} dataBefore={}: NOT IMPLEMENTED YET", id, dataBefore); + final String subInterfaceName = getSubInterfaceName(id); + final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); + LOG.debug("Removing ACLs for sub-interface={}(id={}): {}", subInterfaceName, subInterfaceIndex, dataBefore); + aclWriter.deleteAcl(id, subInterfaceIndex); } } diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriter.java deleted file mode 100644 index c0e79f194..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import com.google.common.annotations.VisibleForTesting; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.util.Collections; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.matches.ace.type.AceEth; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class AceEthWriter implements AceWriter, AclTranslator, L2AclTranslator { - - @VisibleForTesting - static final int MATCH_N_VECTORS = 1; - private static final Logger LOG = LoggerFactory.getLogger(AceEthWriter.class); - - @Override - public ClassifyAddDelTable createTable(@Nonnull final AceEth aceEth, - @Nullable final InterfaceMode mode, - final int nextTableIndex, - final int vlanTags) { - final ClassifyAddDelTable request = createTable(nextTableIndex); - - request.mask = new byte[16]; - boolean aceIsEmpty = - destinationMacAddressMask(aceEth.getDestinationMacAddressMask(), aceEth.getDestinationMacAddress(), - request); - aceIsEmpty &= - sourceMacAddressMask(aceEth.getSourceMacAddressMask(), aceEth.getSourceMacAddress(), request); - - if (aceIsEmpty) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", aceEth.toString())); - } - - request.skipNVectors = 0; - request.matchNVectors = MATCH_N_VECTORS; - - LOG.debug("ACE rule={} translated to table={}.", aceEth, request); - return request; - } - - @Override - public List createSession(@Nonnull final PacketHandling action, - @Nonnull final AceEth aceEth, - @Nullable final InterfaceMode mode, - final int tableIndex, - final int vlanTags) { - final ClassifyAddDelSession request = createSession(action, tableIndex); - - request.match = new byte[16]; - boolean noMatch = destinationMacAddressMatch(aceEth.getDestinationMacAddress(), request); - noMatch &= sourceMacAddressMatch(aceEth.getSourceMacAddress(), request); - - if (noMatch) { - throw new IllegalArgumentException( - String.format("Ace %s does not define neither source nor destination MAC address", - aceEth.toString())); - } - - LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceEth, request); - return Collections.singletonList(request); - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4Writer.java deleted file mode 100644 index ceef19244..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4Writer.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.annotations.VisibleForTesting; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class AceIp4Writer implements AceWriter, AclTranslator, Ip4AclTranslator { - - @VisibleForTesting - static final int MATCH_N_VECTORS = 3; // number of 16B vectors - private static final int TABLE_MASK_LENGTH = 48; - private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class); - - @Override - public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp, - @Nullable final InterfaceMode mode, - final int nextTableIndex, - final int vlanTags) { - checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp); - final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion(); - - final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size(); - final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions); - request.skipNVectors = 0; // match entire L2 and L3 header - request.matchNVectors = MATCH_N_VECTORS; - request.mask = new byte[TABLE_MASK_LENGTH]; - - final int baseOffset = getVlanTagsLen(vlanTags); - boolean aceIsEmpty = ip4Mask(baseOffset, mode, aceIp, ipVersion, request); - if (aceIsEmpty) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", aceIp.toString())); - } - - LOG.debug("ACE rule={} translated to table={}.", aceIp, request); - return request; - } - - @Override - public List createSession(@Nonnull final PacketHandling action, - @Nonnull final AceIp aceIp, - @Nullable final InterfaceMode mode, - final int tableIndex, - final int vlanTags) { - checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp); - final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion(); - - final List portPairs = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()); - final List requests = new ArrayList<>(portPairs.size()); - for (final PortPair pair : portPairs) { - final ClassifyAddDelSession request = createSession(action, tableIndex); - request.match = new byte[TABLE_MASK_LENGTH]; - - final int baseOffset = getVlanTagsLen(vlanTags); - boolean noMatch = ip4Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request); - if (noMatch) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", aceIp.toString())); - } - - LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request); - requests.add(request); - } - return requests; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6Writer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6Writer.java deleted file mode 100644 index 143fcb238..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6Writer.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static com.google.common.base.Preconditions.checkArgument; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class AceIp6Writer implements AceWriter, AclTranslator, Ip6AclTranslator { - - private static final Logger LOG = LoggerFactory.getLogger(AceIp6Writer.class); - - @Override - public ClassifyAddDelTable createTable(@Nonnull final AceIp aceIp, - @Nullable final InterfaceMode mode, - final int nextTableIndex, - final int vlanTags) { - checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp); - final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion(); - - final int numberOfSessions = PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()).size(); - final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions); - request.skipNVectors = 0; // match entire L2 and L3 header - request.mask = new byte[getTableMaskLength(vlanTags)]; - request.matchNVectors = request.mask.length/16; - - final int baseOffset = getVlanTagsLen(vlanTags); - boolean aceIsEmpty = ip6Mask(baseOffset, mode, aceIp, ipVersion, request); - if (aceIsEmpty) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", aceIp.toString())); - } - - LOG.debug("ACE rule={} translated to table={}.", aceIp, request); - return request; - } - - private static int getTableMaskLength(final int vlanTags) { - if (vlanTags == 2) { - return 80; - } else { - return 64; - } - } - - @Override - public List createSession(@Nonnull final PacketHandling action, - @Nonnull final AceIp aceIp, - @Nullable final InterfaceMode mode, - final int tableIndex, - final int vlanTags) { - checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp); - final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion(); - final List portPairs = - PortPair.fromRange(aceIp.getSourcePortRange(), aceIp.getDestinationPortRange()); - - final List requests = new ArrayList<>(portPairs.size()); - for (final PortPair pair : portPairs) { - final ClassifyAddDelSession request = createSession(action, tableIndex); - request.match = new byte[getTableMaskLength(vlanTags)]; - - final int baseOffset = getVlanTagsLen(vlanTags); - boolean noMatch = ip6Match(baseOffset, mode, aceIp, ipVersion, pair.getSrc(), pair.getDst(), request); - if (noMatch) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", aceIp.toString())); - } - - LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request); - requests.add(request); - } - return requests; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriter.java deleted file mode 100644 index 83a9848c9..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriter.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static com.google.common.base.Preconditions.checkArgument; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; -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.AceIpAndEth; -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.ace.ip.and.eth.AceIpVersion; -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.ace.ip.and.eth.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.ace.ip.and.eth.ace.ip.version.AceIpv6; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -final class AceIpAndEthWriter - implements AceWriter, AclTranslator, L2AclTranslator, Ip4AclTranslator, Ip6AclTranslator { - - private static final Logger LOG = LoggerFactory.getLogger(AceIpAndEthWriter.class); - - private static int maskLength(@Nonnull final AceIpAndEth ace, final int vlanTags) { - if (ace.getAceIpVersion() != null) { - if (ace.getAceIpVersion() instanceof AceIpv4) { - return 48; - } else { - return vlanTags == 2 - ? 80 - : 64; - } - } - return 16; - } - - @Override - public ClassifyAddDelTable createTable(@Nonnull final AceIpAndEth ace, @Nullable final InterfaceMode mode, - final int nextTableIndex, final int vlanTags) { - final int numberOfSessions = PortPair.fromRange(ace.getSourcePortRange(), ace.getDestinationPortRange()).size(); - final ClassifyAddDelTable request = createTable(nextTableIndex, numberOfSessions); - final int maskLength = maskLength(ace, vlanTags); - request.mask = new byte[maskLength]; - request.skipNVectors = 0; - request.matchNVectors = maskLength / 16; - - boolean aceIsEmpty = - destinationMacAddressMask(ace.getDestinationMacAddressMask(), ace.getDestinationMacAddress(), request); - aceIsEmpty &= sourceMacAddressMask(ace.getSourceMacAddressMask(), ace.getSourceMacAddress(), request); - - // if we use classifier API, we need to know ip version (fields common for ip4 and ip6 have different offsets): - final AceIpVersion aceIpVersion = ace.getAceIpVersion(); - checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion"); - - final int baseOffset = getVlanTagsLen(vlanTags); - if (aceIpVersion instanceof AceIpv4) { - final AceIpv4 ipVersion = (AceIpv4) aceIpVersion; - aceIsEmpty &= ip4Mask(baseOffset, mode, ace, ipVersion, request); - } else if (aceIpVersion instanceof AceIpv6) { - final AceIpv6 ipVersion = (AceIpv6) aceIpVersion; - aceIsEmpty &= ip6Mask(baseOffset, mode, ace, ipVersion, request); - } else { - throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion)); - } - - if (aceIsEmpty) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", ace.toString())); - } - - LOG.debug("ACE rule={} translated to table={}.", ace, request); - return request; - } - - @Override - public List createSession(@Nonnull final PacketHandling action, - @Nonnull final AceIpAndEth ace, - @Nullable final InterfaceMode mode, final int tableIndex, - final int vlanTags) { - final List portPairs = PortPair.fromRange(ace.getSourcePortRange(), ace.getDestinationPortRange()); - final List requests = new ArrayList<>(portPairs.size()); - for (final PortPair pair : portPairs) { - final ClassifyAddDelSession request = createSession(action, tableIndex); - request.match = new byte[maskLength(ace, vlanTags)]; - - boolean noMatch = destinationMacAddressMatch(ace.getDestinationMacAddress(), request); - noMatch &= sourceMacAddressMatch(ace.getSourceMacAddress(), request); - - final AceIpVersion aceIpVersion = ace.getAceIpVersion(); - checkArgument(aceIpVersion != null, "AceIpAndEth have to define IpVersion"); - - final int baseOffset = getVlanTagsLen(vlanTags); - if (aceIpVersion instanceof AceIpv4) { - final AceIpv4 ipVersion = (AceIpv4) aceIpVersion; - noMatch &= ip4Match(baseOffset, mode, ace, ipVersion, pair.getSrc(), pair.getDst(), request); - } else if (aceIpVersion instanceof AceIpv6) { - final AceIpv6 ipVersion = (AceIpv6) aceIpVersion; - noMatch &= ip6Match(baseOffset, mode, ace, ipVersion, pair.getSrc(), pair.getDst(), request); - } else { - throw new IllegalArgumentException(String.format("Unsupported IP version %s", aceIpVersion)); - } - - if (noMatch) { - throw new IllegalArgumentException( - String.format("Ace %s does not define packet field match values", ace.toString())); - } - LOG.debug("ACE action={}, rule={} translated to session={}.", action, ace, request); - requests.add(request); - } - return requests; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceWriter.java deleted file mode 100644 index bc0b435bd..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceWriter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.util.List; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -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.matches.AceType; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; - -/** - * Writer responsible for translation of ietf-acl model ACEs to VPP's classify tables and sessions. - * - * @param type of access control list entry - */ -interface AceWriter { - /** - * @param ace access list entry - * @param mode interface mode (L2/L3) - * @param nextTableIndex index of the next classify table in chain - * @param vlanTags number of vlan tags - */ - @Nonnull - ClassifyAddDelTable createTable(@Nonnull final T ace, @Nullable final InterfaceMode mode, final int nextTableIndex, - final int vlanTags); - - /** - * @param action to be taken when packet does match the specified ace - * @param ace access list entry - * @param mode interface mode (L2/L3) - * @param tableIndex index of corresponding classify table - * @param vlanTags number of vlan tags - */ - @Nonnull - List createSession(@Nonnull final PacketHandling action, @Nonnull T ace, - @Nullable final InterfaceMode mode, final int tableIndex, final int vlanTags); -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AclTranslator.java deleted file mode 100644 index 44e4622d8..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AclTranslator.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static com.google.common.base.Preconditions.checkArgument; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import javax.annotation.Nonnegative; -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.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.Permit; - -/** - * Utility that helps translating of ietf-acl model ACEs to VPP's classify tables and sessions. - */ -interface AclTranslator { - int TABLE_MEM_SIZE = 8 * 1024; - int VLAN_TAG_LEN = 4; - - default ClassifyAddDelTable createTable(final int nextTableIndex) { - return createTable(nextTableIndex, 1); - } - - default ClassifyAddDelTable createTable(final int nextTableIndex, @Nonnegative final int numberOfSessions) { - final ClassifyAddDelTable request = new ClassifyAddDelTable(); - request.isAdd = 1; - request.tableIndex = -1; // value not present - request.nbuckets = numberOfSessions; - request.nextTableIndex = nextTableIndex; - - - // TODO: HONEYCOMB-181 minimise memory used by classify tables (we create a lot of them to make ietf-acl model - // mapping more convenient): - // according to https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers#Creating_a_classifier_table, - // classify table needs 16*(1 + match_n_vectors) bytes, but this does not quite work, - // so setting 8K +1k*numberOfSessions for now - checkArgument(numberOfSessions>0, "negative numberOfSessions %s", numberOfSessions); - request.memorySize = TABLE_MEM_SIZE+1024*(numberOfSessions-1); - request.missNextIndex = -1; // value not set, but anyway it is ignored for tables in chain - return request; - } - - default ClassifyAddDelSession createSession(@Nonnull final PacketHandling action, final int tableIndex) { - final ClassifyAddDelSession request = new ClassifyAddDelSession(); - request.isAdd = 1; - request.tableIndex = tableIndex; - request.opaqueIndex = ~0; // value not used - - if (action instanceof Permit) { - request.hitNextIndex = -1; - } // deny (0) is default value - - return request; - } - - default int getVlanTagsLen(final int vlanTags) { - return vlanTags * VLAN_TAG_LEN; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizer.java index 4eac0fad6..f4f3d1384 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizer.java @@ -25,8 +25,8 @@ import io.fd.honeycomb.translate.write.WriteContext; import io.fd.honeycomb.translate.write.WriteFailedException; 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.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev161214.interfaces._interface.ietf.acl.Ingress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,10 +41,10 @@ import org.slf4j.LoggerFactory; public class IetfAclCustomizer implements WriterCustomizer { private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class); - private final IetfAclWriter aclWriter; + private final IngressIetfAclWriter aclWriter; private final NamingContext interfaceContext; - public IetfAclCustomizer(@Nonnull final IetfAclWriter aclWriter, + public IetfAclCustomizer(@Nonnull final IngressIetfAclWriter aclWriter, @Nonnull final NamingContext interfaceContext) { this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null"); this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclWriter.java deleted file mode 100644 index c74845ce7..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclWriter.java +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static com.google.common.base.Preconditions.checkArgument; - -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer; -import io.fd.honeycomb.translate.write.WriteContext; -import io.fd.honeycomb.translate.write.WriteFailedException; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSessionReply; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTableReply; -import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface; -import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply; -import io.fd.vpp.jvpp.core.dto.InputAclSetInterface; -import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply; -import io.fd.vpp.jvpp.core.future.FutureJVppCore; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.concurrent.CompletionStage; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.AccessListEntries; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.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.matches.AceType; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.AceIpVersion; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; -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.AceIpAndEth; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class IetfAclWriter implements JvppReplyConsumer, AclTranslator { - - private static final Logger LOG = LoggerFactory.getLogger(IetfAclWriter.class); - private static final int NOT_DEFINED = -1; - private final FutureJVppCore jvpp; - - private Map> aceWriters = new HashMap<>(); - - public IetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) { - this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null"); - aceWriters.put(AclType.ETH, new AceEthWriter()); - aceWriters.put(AclType.IP4, new AceIp4Writer()); - aceWriters.put(AclType.IP6, new AceIp6Writer()); - aceWriters.put(AclType.ETH_AND_IP, new AceIpAndEthWriter()); - } - - private static Stream aclToAceStream(@Nonnull final Acl assignedAcl, - @Nonnull final WriteContext writeContext) { - final String aclName = assignedAcl.getName(); - final Class aclType = assignedAcl.getType(); - - // ietf-acl updates are handled first, so we use writeContext.readAfter - final Optional - aclOptional = - writeContext.readAfter(io.fd.honeycomb.translate.v3po.interfaces.acl.IetfAclWriter.ACL_ID.child( - org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl.class, - new AclKey(aclName, aclType))); - checkArgument(aclOptional.isPresent(), "Acl lists not configured"); - final org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl - acl = aclOptional.get(); - - final AccessListEntries accessListEntries = acl.getAccessListEntries(); - checkArgument(accessListEntries != null, "access list entries not configured"); - - return accessListEntries.getAce().stream(); - } - - void deleteAcl(@Nonnull final InstanceIdentifier id, final int swIfIndex) - throws WriteFailedException { - final ClassifyTableByInterface request = new ClassifyTableByInterface(); - request.swIfIndex = swIfIndex; - - final CompletionStage cs = jvpp.classifyTableByInterface(request); - final ClassifyTableByInterfaceReply reply = getReplyForDelete(cs.toCompletableFuture(), id); - - // We unassign and remove all ACL-related classify tables for given interface (we assume we are the only - // classify table manager) - - unassignClassifyTables(id, reply); - - removeClassifyTable(id, reply.l2TableId); - removeClassifyTable(id, reply.ip4TableId); - removeClassifyTable(id, reply.ip6TableId); - } - - private void unassignClassifyTables(@Nonnull final InstanceIdentifier id, - final ClassifyTableByInterfaceReply currentState) - throws WriteFailedException { - final InputAclSetInterface request = new InputAclSetInterface(); - request.isAdd = 0; - request.swIfIndex = currentState.swIfIndex; - request.l2TableIndex = currentState.l2TableId; - request.ip4TableIndex = currentState.ip4TableId; - request.ip6TableIndex = currentState.ip6TableId; - final CompletionStage inputAclSetInterfaceReplyCompletionStage = - jvpp.inputAclSetInterface(request); - getReplyForDelete(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); - } - - private void removeClassifyTable(@Nonnull final InstanceIdentifier id, final int tableIndex) - throws WriteFailedException { - - if (tableIndex == -1) { - return; // classify table id is absent - } - final ClassifyAddDelTable request = new ClassifyAddDelTable(); - request.tableIndex = tableIndex; - final CompletionStage cs = jvpp.classifyAddDelTable(request); - getReplyForDelete(cs.toCompletableFuture(), id); - } - - void write(@Nonnull final InstanceIdentifier id, final int swIfIndex, @Nonnull final List acls, - final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode, - @Nonnull final WriteContext writeContext) - throws WriteFailedException { - write(id, swIfIndex, mode, acls, defaultAction, writeContext, 0); - } - - private static boolean appliesToIp4Path(final Ace ace) { - final AceType aceType = ace.getMatches().getAceType(); - final AclType aclType = AclType.fromAce(ace); - if (aclType == AclType.IP4) { - return true; - } - if (aclType == AclType.ETH) { - return true; // L2 only rules are possible for IP4 traffic - } - if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType) - .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv4) { - return true; - } - return false; - } - - private static boolean appliesToIp6Path(final Ace ace) { - final AceType aceType = ace.getMatches().getAceType(); - final AclType aclType = AclType.fromAce(ace); - if (aclType == AclType.IP6) { - return true; - } - if (aclType == AclType.ETH) { - return true; // L2 only rules are possible for IP6 traffic - } - if (aclType == AclType.ETH_AND_IP && ((AceIpAndEth) aceType) - .getAceIpVersion() instanceof org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.and.eth.ace.ip.version.AceIpv6) { - return true; - } - return false; - } - - void write(@Nonnull final InstanceIdentifier id, final int swIfIndex, final InterfaceMode mode, - @Nonnull final List acls, final AccessLists.DefaultAction defaultAction, - @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags) - throws WriteFailedException { - checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range"); - - final InputAclSetInterface request = new InputAclSetInterface(); - request.isAdd = 1; - request.swIfIndex = swIfIndex; - request.l2TableIndex = NOT_DEFINED; - request.ip4TableIndex = NOT_DEFINED; - request.ip6TableIndex = NOT_DEFINED; - - if (InterfaceMode.L2.equals(mode)) { - final List aces = getACEs(acls, writeContext, ace -> true); - request.l2TableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags); - } else { - final List ip4Aces = getACEs(acls, writeContext, (IetfAclWriter::appliesToIp4Path)); - request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags); - final List ip6Aces = getACEs(acls, writeContext, (IetfAclWriter::appliesToIp6Path)); - request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags); - } - - final CompletionStage inputAclSetInterfaceReplyCompletionStage = - jvpp.inputAclSetInterface(request); - getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); - } - - private static List getACEs(@Nonnull final List acls, @Nonnull final WriteContext writeContext, - final Predicate filter) { - return acls.stream().flatMap(acl -> aclToAceStream(acl, writeContext)).filter(filter) - .collect(Collectors.toList()); - } - - private int writeAces(final InstanceIdentifier id, final List aces, - final AccessLists.DefaultAction defaultAction, final InterfaceMode mode, - final int vlanTags) throws WriteFailedException { - if (aces.isEmpty()) { - return NOT_DEFINED; - } - - int nextTableIndex = configureDefaultAction(id, defaultAction); - final ListIterator iterator = aces.listIterator(aces.size()); - while (iterator.hasPrevious()) { - final Ace ace = iterator.previous(); - LOG.trace("Processing ACE: {}", ace); - - final AceWriter aceWriter = - aceWriters.get(AclType.fromAce(ace)); - if (aceWriter == null) { - LOG.warn("AceProcessor for {} not registered. Skipping ACE.", ace.getClass()); - } else { - final AceType aceType = ace.getMatches().getAceType(); - final PacketHandling action = ace.getActions().getPacketHandling(); - final ClassifyAddDelTable ctRequest = aceWriter.createTable(aceType, mode, nextTableIndex, vlanTags); - nextTableIndex = createClassifyTable(id, ctRequest); - final List sessionRequests = - aceWriter.createSession(action, aceType, mode, nextTableIndex, vlanTags); - for (ClassifyAddDelSession csRequest : sessionRequests) { - createClassifySession(id, csRequest); - } - } - } - return nextTableIndex; - } - - private int configureDefaultAction(@Nonnull final InstanceIdentifier id, - final AccessLists.DefaultAction defaultAction) - throws WriteFailedException { - ClassifyAddDelTable ctRequest = createTable(-1); - if (AccessLists.DefaultAction.Permit.equals(defaultAction)) { - ctRequest.missNextIndex = -1; - } else { - ctRequest.missNextIndex = 0; - } - ctRequest.mask = new byte[16]; - ctRequest.skipNVectors = 0; - ctRequest.matchNVectors = 1; - return createClassifyTable(id, ctRequest); - } - - private int createClassifyTable(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyAddDelTable request) - throws WriteFailedException { - final CompletionStage cs = jvpp.classifyAddDelTable(request); - - final ClassifyAddDelTableReply reply = getReplyForWrite(cs.toCompletableFuture(), id); - return reply.newTableIndex; - } - - private void createClassifySession(@Nonnull final InstanceIdentifier id, - @Nonnull final ClassifyAddDelSession request) - throws WriteFailedException { - final CompletionStage cs = jvpp.classifyAddDelSession(request); - - getReplyForWrite(cs.toCompletableFuture(), id); - } - - private enum AclType { - ETH, IP4, IP6, ETH_AND_IP; - - @Nonnull - private static AclType fromAce(final Ace ace) { - AclType result = null; - final AceType aceType; - try { - aceType = ace.getMatches().getAceType(); - if (aceType instanceof AceEth) { - result = ETH; - } else if (aceType instanceof AceIp) { - final AceIpVersion aceIpVersion = ((AceIp) aceType).getAceIpVersion(); - if (aceIpVersion == null) { - throw new IllegalArgumentException("Incomplete ACE (ip-version was not provided): " + ace); - } - if (aceIpVersion instanceof AceIpv4) { - result = IP4; - } else if (aceIpVersion instanceof AceIpv6) { - result = IP6; - } - } else if (aceType instanceof AceIpAndEth) { - result = ETH_AND_IP; - } - } catch (NullPointerException e) { - throw new IllegalArgumentException("Incomplete ACE: " + ace, e); - } - if (result == null) { - throw new IllegalArgumentException(String.format("Not supported ace type %s", aceType)); - } - return result; - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java new file mode 100644 index 000000000..969ac43f4 --- /dev/null +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IngressIetfAclWriter.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; + +import static com.google.common.base.Preconditions.checkArgument; + +import io.fd.honeycomb.translate.v3po.interfaces.acl.common.AbstractIetfAclWriter; +import io.fd.honeycomb.translate.write.WriteContext; +import io.fd.honeycomb.translate.write.WriteFailedException; +import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterface; +import io.fd.vpp.jvpp.core.dto.ClassifyTableByInterfaceReply; +import io.fd.vpp.jvpp.core.dto.InputAclSetInterface; +import io.fd.vpp.jvpp.core.dto.InputAclSetInterfaceReply; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import java.util.List; +import java.util.concurrent.CompletionStage; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +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.InterfaceMode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.AccessLists; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public final class IngressIetfAclWriter extends AbstractIetfAclWriter { + + private static final int NOT_DEFINED = -1; + + public IngressIetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) { + super(futureJVppCore); + } + + @Override + public void deleteAcl(@Nonnull final InstanceIdentifier id, final int swIfIndex) + throws WriteFailedException { + final ClassifyTableByInterface request = new ClassifyTableByInterface(); + request.swIfIndex = swIfIndex; + + final CompletionStage cs = jvpp.classifyTableByInterface(request); + final ClassifyTableByInterfaceReply reply = getReplyForDelete(cs.toCompletableFuture(), id); + + // We unassign and remove all ACL-related classify tables for given interface (we assume we are the only + // classify table manager) + + unassignClassifyTables(id, reply); + + removeClassifyTable(id, reply.l2TableId); + removeClassifyTable(id, reply.ip4TableId); + removeClassifyTable(id, reply.ip6TableId); + } + + private void unassignClassifyTables(@Nonnull final InstanceIdentifier id, + final ClassifyTableByInterfaceReply currentState) + throws WriteFailedException { + final InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = 0; + request.swIfIndex = currentState.swIfIndex; + request.l2TableIndex = currentState.l2TableId; + request.ip4TableIndex = currentState.ip4TableId; + request.ip6TableIndex = currentState.ip6TableId; + final CompletionStage inputAclSetInterfaceReplyCompletionStage = + jvpp.inputAclSetInterface(request); + getReplyForDelete(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); + } + + @Override + public void write(@Nonnull final InstanceIdentifier id, int swIfIndex, @Nonnull final List acls, + final AccessLists.DefaultAction defaultAction, @Nullable InterfaceMode mode, + @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags) + throws WriteFailedException { + checkArgument(numberOfTags >= 0 && numberOfTags <= 2, "Number of vlan tags %s is not in [0,2] range"); + + final InputAclSetInterface request = new InputAclSetInterface(); + request.isAdd = 1; + request.swIfIndex = swIfIndex; + request.l2TableIndex = NOT_DEFINED; + request.ip4TableIndex = NOT_DEFINED; + request.ip6TableIndex = NOT_DEFINED; + + if (InterfaceMode.L2.equals(mode)) { + final List aces = getACEs(acls, writeContext, ace -> true); + request.l2TableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags); + } else { + final List ip4Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp4Path)); + request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags); + final List ip6Aces = getACEs(acls, writeContext, (AbstractIetfAclWriter::appliesToIp6Path)); + request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags); + } + + final CompletionStage inputAclSetInterfaceReplyCompletionStage = + jvpp.inputAclSetInterface(request); + getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id); + } +} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip4AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip4AclTranslator.java deleted file mode 100644 index 55d73fccb..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip4AclTranslator.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import com.google.common.primitives.Ints; -import io.fd.honeycomb.translate.vpp.util.Ipv4Translator; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv4HeaderFields; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; - -public interface Ip4AclTranslator extends Ipv4Translator { - int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6) - int DSCP_OFFSET = 15; - int DSCP_MASK = 0xfc; - - int IP_PROTOCOL_OFFSET = ETHER_TYPE_OFFSET + 11; - int IP_PROTOCOL_MASK = 0xff; - - int IP4_LEN = 4; - int IP4_MASK_BIT_LENGTH = 32; - int SRC_IP_OFFSET = ETHER_TYPE_OFFSET + 14; - int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN; - int SRC_PORT_OFFSET = DST_IP_OFFSET + IP4_LEN; - int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2; - - default boolean ip4Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, - final AclIpv4HeaderFields ip4, final ClassifyAddDelTable request) { - boolean aceIsEmpty = true; - if (InterfaceMode.L2.equals(mode)) { - // in L2 mode we need to match ether type - request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff; - request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff; - } - if (header.getDscp() != null) { - aceIsEmpty = false; - request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits - } - if (header.getProtocol() != null) { // Internet Protocol number - aceIsEmpty = false; - request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK; - } - if (header.getSourcePortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - aceIsEmpty = false; - request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff; - request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff; - } - if (header.getDestinationPortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - aceIsEmpty = false; - request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff; - request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff; - } - if (ip4.getSourceIpv4Network() != null) { - aceIsEmpty = false; - System.arraycopy(Impl.toByteMask(ip4.getSourceIpv4Network()), 0, request.mask, - baseOffset + SRC_IP_OFFSET, IP4_LEN); - } - if (ip4.getDestinationIpv4Network() != null) { - aceIsEmpty = false; - System.arraycopy(Impl.toByteMask(ip4.getDestinationIpv4Network()), 0, request.mask, - baseOffset + DST_IP_OFFSET, IP4_LEN); - } - return aceIsEmpty; - } - - default boolean ip4Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, - final AclIpv4HeaderFields ip4, final Integer srcPort, - final Integer dstPort, final ClassifyAddDelSession request) { - boolean noMatch = true; - if (InterfaceMode.L2.equals(mode)) { - // match IP4 etherType (0x0800) - request.match[baseOffset + ETHER_TYPE_OFFSET] = 0x08; - request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = 0x00; - } - if (header.getDscp() != null) { - noMatch = false; - request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (header.getDscp().getValue() << 2)); - } - if (header.getProtocol() != null) { // Internet Protocol number - noMatch = false; - request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol()); - } - if (srcPort != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - noMatch = false; - request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8); - request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort); - } - if (header.getDestinationPortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - noMatch = false; - request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8); - request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort); - } - if (ip4.getSourceIpv4Network() != null) { - noMatch = false; - System.arraycopy(Impl.toMatchValue(ip4.getSourceIpv4Network()), 0, request.match, - baseOffset + SRC_IP_OFFSET, IP4_LEN); - - } - if (ip4.getDestinationIpv4Network() != null) { - noMatch = false; - System.arraycopy(Impl.toMatchValue(ip4.getDestinationIpv4Network()), 0, request.match, - baseOffset + DST_IP_OFFSET, IP4_LEN); - - } - return noMatch; - } - - class Impl { - private static byte[] toByteMask(final int prefixLength) { - final long mask = ((1L << prefixLength) - 1) << (IP4_MASK_BIT_LENGTH - prefixLength); - return Ints.toByteArray((int) mask); - } - - private static byte[] toByteMask(final Ipv4Prefix ipv4Prefix) { - final int prefixLength = Byte.valueOf(ipv4Prefix.getValue().split("/")[1]); - return toByteMask(prefixLength); - } - - private static byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) { - final String[] split = ipv4Prefix.getValue().split("/"); - final byte[] addressBytes = Ipv4Translator.INSTANCE.ipv4AddressNoZoneToArray(split[0]); - final byte[] mask = Impl.toByteMask(Byte.valueOf(split[1])); - for (int i = 0; i < addressBytes.length; ++i) { - addressBytes[i] &= mask[i]; - } - return addressBytes; - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip6AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip6AclTranslator.java deleted file mode 100644 index 9dfab31c2..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip6AclTranslator.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.BitSet; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields; -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.InterfaceMode; - -public interface Ip6AclTranslator { - - int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6) - int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET + 2; - int DSCP_MASK1 = 0x0f; - int DSCP_MASK2 = 0xc0; - int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET + 6; - int IP_PROTOCOL_MASK = 0xff; - int IP6_LEN = 16; - int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8; - int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN; - int SRC_PORT_OFFSET = DST_IP_OFFSET + IP6_LEN; - int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2; - - default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, - final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request) { - boolean aceIsEmpty = true; - if (InterfaceMode.L2.equals(mode)) { - // in L2 mode we need to match ether type - request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff; - request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff; - } - if (header.getDscp() != null) { - aceIsEmpty = false; - // DCSP (bits 4-9 of IP6 header) - request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1; - request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2; - } - if (header.getProtocol() != null) { // Internet Protocol number - aceIsEmpty = false; - request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK; - } - if (ip6.getFlowLabel() != null) { - aceIsEmpty = false; - // bits 12-31 - request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) 0x0f; - request.mask[baseOffset + IP_VERSION_OFFSET + 2] = (byte) 0xff; - request.mask[baseOffset + IP_VERSION_OFFSET + 3] = (byte) 0xff; - } - if (header.getSourcePortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - aceIsEmpty = false; - request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff; - request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff; - } - if (header.getDestinationPortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - aceIsEmpty = false; - request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff; - request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff; - } - if (ip6.getSourceIpv6Network() != null) { - aceIsEmpty = false; - final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network()); - System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length); - } - if (ip6.getDestinationIpv6Network() != null) { - aceIsEmpty = false; - final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network()); - System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length); - } - return aceIsEmpty; - } - - default boolean ip6Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header, - final AclIpv6HeaderFields ip6, final Integer srcPort, final Integer dstPort, final ClassifyAddDelSession request) { - boolean noMatch = true; - if (InterfaceMode.L2.equals(mode)) { - // match IP6 etherType (0x86dd) - request.match[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0x86; - request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xdd; - } - if (header.getDscp() != null) { - noMatch = false; - final int dcsp = header.getDscp().getValue(); - // set bits 4-9 of IP6 header: - request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dcsp >> 2)); - request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dcsp << 6)); - } - if (header.getProtocol() != null) { // Internet Protocol number - noMatch = false; - request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol()); - } - if (ip6.getFlowLabel() != null) { - noMatch = false; - final int flowLabel = ip6.getFlowLabel().getValue().intValue(); - // bits 12-31 - request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16)); - request.match[baseOffset + IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8)); - request.match[baseOffset + IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel); - } - if (header.getSourcePortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - noMatch = false; - request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8); - request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort); - } - if (header.getDestinationPortRange() != null) { - // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present - noMatch = false; - request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8); - request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort); - } - if (ip6.getSourceIpv6Network() != null) { - noMatch = false; - final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network()); - System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN); - } - if (ip6.getDestinationIpv6Network() != null) { - noMatch = false; - final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network()); - System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN); - } - return noMatch; - } - - class Impl { - private static final int IP6_MASK_BIT_LENGTH = 128; - - private static byte[] toByteMask(final int prefixLength) { - final BitSet mask = new BitSet(IP6_MASK_BIT_LENGTH); - mask.set(0, prefixLength, true); - if (prefixLength < IP6_MASK_BIT_LENGTH) { - mask.set(prefixLength, IP6_MASK_BIT_LENGTH, false); - } - return mask.toByteArray(); - } - - private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) { - final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]); - return toByteMask(prefixLength); - } - - private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) { - final String[] split = ipv6Prefix.getValue().split("/"); - final byte[] addressBytes; - try { - addressBytes = InetAddress.getByName(split[0]).getAddress(); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Invalid IP6 address", e); - } - final byte[] mask = toByteMask(Short.valueOf(split[1])); - int pos = 0; - for (; pos < mask.length; ++pos) { - addressBytes[pos] &= mask[pos]; - } - // mask can be shorter that address, so we need to clear rest of the address: - for (; pos < addressBytes.length; ++pos) { - addressBytes[pos] = 0; - } - return addressBytes; - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/L2AclTranslator.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/L2AclTranslator.java deleted file mode 100644 index a802ed3fa..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/L2AclTranslator.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import io.fd.honeycomb.translate.vpp.util.MacTranslator; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import java.util.List; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; - -public interface L2AclTranslator extends MacTranslator { - - default boolean destinationMacAddressMask(final MacAddress dstMask, final MacAddress dstAddress, - final ClassifyAddDelTable request) { - // destination-mac-address or destination-mac-address-mask is present => - // ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00 - if (dstMask != null) { - final List parts = COLON_SPLITTER.splitToList(dstMask.getValue()); - int i = 0; - for (String part : parts) { - request.mask[i++] = parseHexByte(part); - } - return false; - } else if (dstAddress != null) { - for (int i = 0; i < 6; ++i) { - request.mask[i] = (byte) 0xff; - } - return false; - } - return true; - } - - default boolean sourceMacAddressMask(final MacAddress srcMask, final MacAddress srcAddress, - final ClassifyAddDelTable request) { - // source-mac-address or source-mac-address-mask => - // 00:00:00:00:00:00:ff:ff:ff:ff:ff:ff:00:00:00:00 - if (srcMask != null) { - final List parts = COLON_SPLITTER.splitToList(srcMask.getValue()); - int i = 6; - for (String part : parts) { - request.mask[i++] = parseHexByte(part); - } - return false; - } else if (srcAddress != null) { - for (int i = 6; i < 12; ++i) { - request.mask[i] = (byte) 0xff; - } - return false; - } - return true; - } - - default boolean destinationMacAddressMatch(final MacAddress dstAddress, final ClassifyAddDelSession request) { - if (dstAddress != null) { - final List parts = COLON_SPLITTER.splitToList(dstAddress.getValue()); - int i = 0; - for (String part : parts) { - request.match[i++] = parseHexByte(part); - } - return false; - } - return true; - } - - default boolean sourceMacAddressMatch(final MacAddress srcAddress, final ClassifyAddDelSession request) { - if (srcAddress != null) { - final List parts = COLON_SPLITTER.splitToList(srcAddress.getValue()); - int i = 6; - for (String part : parts) { - request.match[i++] = parseHexByte(part); - } - return false; - } - return true; - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPair.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPair.java deleted file mode 100644 index 274303004..000000000 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPair.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.function.BiFunction; -import javax.annotation.Nullable; -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; - -/** - * Utility that produces cartesian product out of src and dst port ranges (used to translate ranges into - * list of classify sessions). - */ -final class PortPair { - private final Integer src; - private final Integer dst; - - PortPair(@Nullable final Integer src, @Nullable final Integer dst) { - this.src = src; - this.dst = dst; - } - - Integer getSrc() { - return src; - } - - Integer getDst() { - return dst; - } - - @Override - public String toString() { - return "(" + src + "," + dst + ")"; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - final PortPair that = (PortPair) o; - if (!Objects.equals(src, that.src)) { - return false; - } - if (!Objects.equals(dst, that.dst)) { - return false; - } - return true; - } - - @Override - public int hashCode() { - return Objects.hash(src, dst); - } - - static List fromRange(final SourcePortRange srcRange, - final DestinationPortRange dstRange) { - final List result = new ArrayList<>(); - if (srcRange == null && dstRange == null) { - result.add(new PortPair(null, null)); - } else if (srcRange != null && dstRange == null) { - processSingleRange(result, srcRange.getLowerPort(), srcRange.getUpperPort(), PortPair::new); - } else if (srcRange == null && dstRange != null) { - processSingleRange(result, dstRange.getLowerPort(), dstRange.getUpperPort(), - (dst, src) -> new PortPair(src, dst)); - } else { - processDoubleRange(result, srcRange, dstRange); - } - return result; - } - - private static void processSingleRange(final List result, - final PortNumber lowerPort, - final PortNumber upperPort, - final BiFunction f) { - int low = lowerPort.getValue(); // mandatory - int hi = low; - if (upperPort != null) { - hi = upperPort.getValue(); - } - for (; low <= hi; ++low) { - result.add(f.apply(low, null)); - } - } - - private static void processDoubleRange(final List result, final SourcePortRange srcRange, - final DestinationPortRange dstRange) { - int srcL = srcRange.getLowerPort().getValue(); - int srcH = srcL; - if (srcRange.getUpperPort() != null) { - srcH = srcRange.getUpperPort().getValue(); - } - int dstL = dstRange.getLowerPort().getValue(); - int dstH = dstL; - if (dstRange.getUpperPort() != null) { - dstH = dstRange.getUpperPort().getValue(); - } - for (int i=srcL; i <= srcH; ++i) { - for (int j=dstL; j <= dstH; ++j) { - result.add(new PortPair(i, j)); - } - } - } -} diff --git a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java index fdefc0855..47b8aba6f 100644 --- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java +++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java @@ -48,10 +48,10 @@ import org.slf4j.LoggerFactory; public class SubInterfaceIetfAclCustomizer implements WriterCustomizer { private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class); - private final IetfAclWriter aclWriter; + private final IngressIetfAclWriter aclWriter; private final NamingContext interfaceContext; - public SubInterfaceIetfAclCustomizer(@Nonnull final IetfAclWriter aclWriter, + public SubInterfaceIetfAclCustomizer(@Nonnull final IngressIetfAclWriter aclWriter, @Nonnull final NamingContext interfaceContext) { this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null"); this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null"); @@ -61,7 +61,7 @@ public class SubInterfaceIetfAclCustomizer implements WriterCustomizer final InterfaceKey parentInterfacekey = id.firstKeyOf(Interface.class); final SubInterfaceKey subInterfacekey = id.firstKeyOf(SubInterface.class); return SubInterfaceUtils - .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); + .getSubInterfaceName(parentInterfacekey.getName(), subInterfacekey.getIdentifier().intValue()); } @Override @@ -73,15 +73,16 @@ public class SubInterfaceIetfAclCustomizer implements WriterCustomizer final AccessLists accessLists = dataAfter.getAccessLists(); checkArgument(accessLists != null && accessLists.getAcl() != null, - "ietf-acl container does not define acl list"); + "ietf-acl container does not define acl list"); final Optional subInterfaceOptional = - writeContext.readAfter(id.firstIdentifierOf(SubInterface.class)); + writeContext.readAfter(id.firstIdentifierOf(SubInterface.class)); checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id); final SubInterface subInterface = subInterfaceOptional.get(); - aclWriter.write(id, subInterfaceIndex, accessLists.getMode(), accessLists.getAcl(), - accessLists.getDefaultAction(), writeContext, getNumberOfTags(subInterface.getTags())); + aclWriter + .write(id, subInterfaceIndex, accessLists.getAcl(), accessLists.getDefaultAction(), accessLists.getMode(), + writeContext, getNumberOfTags(subInterface.getTags())); } @Override @@ -98,7 +99,7 @@ public class SubInterfaceIetfAclCustomizer implements WriterCustomizer @Override public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier id, @Nonnull final Ingress dataBefore, @Nonnull final WriteContext writeContext) - throws WriteFailedException { + throws WriteFailedException { final String subInterfaceName = getSubInterfaceName(id); final int subInterfaceIndex = interfaceContext.getIndex(subInterfaceName, writeContext.getMappingContext()); LOG.debug("Removing ACLs for sub-interface={}(id={}): {}", subInterfaceName, subInterfaceIndex, dataBefore); diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriterTest.java new file mode 100644 index 000000000..3a50b7673 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceEthWriterTest.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.honeycomb.translate.v3po.interfaces.acl.common; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import org.junit.Before; +import org.junit.Test; +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.DenyBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEthBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; + +public class AceEthWriterTest { + + private AceEthWriter writer; + private PacketHandling action; + private AceEth aceEth; + + @Before + public void setUp() { + initMocks(this); + writer = new AceEthWriter(); + action = new DenyBuilder().setDeny(true).build(); + aceEth = new AceEthBuilder() + .setDestinationMacAddress(new MacAddress("11:22:33:44:55:66")) + .setDestinationMacAddressMask(new MacAddress("ff:ff:ff:ff:ff:ff")) + .setSourceMacAddress(new MacAddress("aa:bb:cc:dd:ee:ff")) + .setSourceMacAddressMask(new MacAddress("ff:ff:ff:00:00:00")) + .build(); + } + + @Test + public void testCreateTable() { + final int nextTableIndex = 42; + final ClassifyAddDelTable request = writer.createTable(aceEth, InterfaceMode.L2, nextTableIndex, 0); + + assertEquals(1, request.isAdd); + assertEquals(-1, request.tableIndex); + assertEquals(1, request.nbuckets); + assertEquals(nextTableIndex, request.nextTableIndex); + assertEquals(0, request.skipNVectors); + assertEquals(AceEthWriter.MATCH_N_VECTORS, request.matchNVectors); + assertEquals(AceEthWriter.TABLE_MEM_SIZE, request.memorySize); + + byte[] expectedMask = new byte[] { + // destination MAC: + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + // source MAC: + (byte) 0xff, (byte) 0xff, (byte) 0xff, 0, 0, 0, + 0, 0, 0, 0 + }; + assertArrayEquals(expectedMask, request.mask); + } + + @Test + public void testCreateClassifySession() { + final int tableIndex = 123; + final ClassifyAddDelSession request = writer.createSession(action, aceEth, InterfaceMode.L2, tableIndex, 0).get(0); + + assertEquals(1, request.isAdd); + assertEquals(tableIndex, request.tableIndex); + assertEquals(0, request.hitNextIndex); + + byte[] expectedMatch = new byte[] { + // destination MAC: + (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + // source MAC: + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, + 0, 0, 0, 0 + }; + assertArrayEquals(expectedMatch, request.match); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4WriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4WriterTest.java new file mode 100644 index 000000000..f3a9d0f87 --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp4WriterTest.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static io.fd.honeycomb.translate.v3po.interfaces.acl.common.AclTranslator.VLAN_TAG_LEN; +import static org.junit.Assert.assertEquals; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import org.junit.Before; +import org.junit.Test; +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.DenyBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +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.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; + +public class AceIp4WriterTest { + + private AceIp4Writer writer; + private PacketHandling action; + private AceIp aceIp; + + @Before + public void setUp() throws Exception { + initMocks(this); + writer = new AceIp4Writer(); + action = new DenyBuilder().setDeny(true).build(); + aceIp = new AceIpBuilder() + .setProtocol((short) 132) + .setDscp(new Dscp((short) 11)) + .setAceIpVersion(new AceIpv4Builder() + .setSourceIpv4Network(new Ipv4Prefix("1.2.3.4/32")) + .setDestinationIpv4Network(new Ipv4Prefix("1.2.4.5/24")) + .build()) + .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) + .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) + .build(); + } + + private static void verifyTableRequest(final ClassifyAddDelTable request, final int nextTableIndex, + final int vlanTags, final boolean isL2) { + assertEquals(1, request.isAdd); + assertEquals(-1, request.tableIndex); + assertEquals(1, request.nbuckets); + assertEquals(nextTableIndex, request.nextTableIndex); + assertEquals(0, request.skipNVectors); + assertEquals(AceIp4Writer.MATCH_N_VECTORS, request.matchNVectors); + assertEquals(AceIp4Writer.TABLE_MEM_SIZE, request.memorySize); + + byte[] expectedMask = new byte[] { + // L2: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // dscp: + (byte) 0x00, (byte) 0xfc, + // protocol: + 0, 0, 0, 0, 0, 0, 0, (byte) 0xff, 0, 0, + // source address: + -1, -1, -1, -1, + // destination address: + -1, -1, -1, 0, + // source and destination port: + -1, -1, -1, -1, + // padding: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (isL2) { + expectedMask[12] = (byte) 0xff; + expectedMask[13] = (byte) 0xff; + } + AceIpWriterTestUtils + .assertArrayEqualsWithOffset(expectedMask, expectedMask.length, request.mask, vlanTags * VLAN_TAG_LEN); + + } + + private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex, + final int vlanTags, final boolean isL2) { + assertEquals(1, request.isAdd); + assertEquals(tableIndex, request.tableIndex); + assertEquals(0, request.hitNextIndex); + + byte[] expectedMatch = new byte[] { + // L2: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // dscp: + 0, (byte) 0x2c, + // protocol (132): + 0, 0, 0, 0, 0, 0, 0, (byte) 132, 0, 0, + // source address: + 1, 2, 3, 4, + // destination address: + 1, 2, 4, 0, + // source and destination port: + 0x11, 0x11, 0x22, 0x22, + // padding: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + if (isL2) { + expectedMatch[12] = (byte) 0x08; + expectedMatch[13] = (byte) 0x00; + } + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, expectedMatch.length, request.match, vlanTags * VLAN_TAG_LEN); + + } + + @Test + public void testCreateTable() throws Exception { + final int nextTableIndex = 42; + final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, 0); + verifyTableRequest(request, nextTableIndex, 0, false); + } + + @Test + public void testCreateTableForL2Interface() throws Exception { + final int nextTableIndex = 42; + final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L2, nextTableIndex, 0); + verifyTableRequest(request, nextTableIndex, 0, true); + } + + @Test + public void testCreateTable1VlanTag() throws Exception { + final int nextTableIndex = 42; + final int vlanTags = 1; + final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); + verifyTableRequest(request, nextTableIndex, vlanTags, false); + } + + @Test + public void testCreateTable2VlanTags() throws Exception { + final int nextTableIndex = 42; + final int vlanTags = 2; + final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); + verifyTableRequest(request, nextTableIndex, vlanTags, false); + } + + @Test + public void testCreateClassifySession() throws Exception { + final int tableIndex = 123; + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0).get(0); + verifySessionRequest(request, tableIndex, 0, false); + } + + @Test + public void testCreateClassifySessionForL2Interface() throws Exception { + final int tableIndex = 123; + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0).get(0); + verifySessionRequest(request, tableIndex, 0, true); + } + + @Test + public void testCreateClassifySession1VlanTag() throws Exception { + final int tableIndex = 123; + final int vlanTags = 1; + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); + verifySessionRequest(request, tableIndex, vlanTags, false); + } + + @Test + public void testCreateClassifySession2VlanTags() throws Exception { + final int tableIndex = 123; + final int vlanTags = 2; + final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); + + verifySessionRequest(request, tableIndex, vlanTags, false); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6WriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6WriterTest.java new file mode 100644 index 000000000..382d8840e --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIp6WriterTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static io.fd.honeycomb.translate.v3po.interfaces.acl.common.AclTranslator.VLAN_TAG_LEN; +import static org.junit.Assert.assertEquals; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import org.junit.Before; +import org.junit.Test; +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.DenyBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6Builder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6FlowLabel; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; +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.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; + +public class AceIp6WriterTest { + + private AceIp6Writer writer; + private PacketHandling action; + private AceIp aceIp; + + @Before + public void setUp() { + initMocks(this); + writer = new AceIp6Writer(); + action = new DenyBuilder().setDeny(true).build(); + aceIp = new AceIpBuilder() + .setProtocol((short) 132) + .setDscp(new Dscp((short) 11)) + .setAceIpVersion(new AceIpv6Builder() + .setFlowLabel(new Ipv6FlowLabel(123L)) + .setSourceIpv6Network(new Ipv6Prefix("2001:db8:85a3:8d3:1319:8a2e:370:7348/128")) + .setDestinationIpv6Network(new Ipv6Prefix("fe80:1234:5678:abcd:ef01::/64")) + .build()) + .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) + .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) + .build(); + } + + + private static void verifyTableRequest(final ClassifyAddDelTable request, final int nextTableIndex, + final int vlanTags, final boolean isL2) { + assertEquals(1, request.isAdd); + assertEquals(-1, request.tableIndex); + assertEquals(1, request.nbuckets); + assertEquals(nextTableIndex, request.nextTableIndex); + assertEquals(0, request.skipNVectors); + assertEquals(vlanTags == 2 ? 5 : 4, request.matchNVectors); + assertEquals(AceIp6Writer.TABLE_MEM_SIZE, request.memorySize); + + byte[] expectedMask = new byte[] { + // L2: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // dscp, flow: + (byte) 0x0f, (byte) 0xcf, (byte) 0xff, (byte) 0xff, + // protocol: + 0, 0, (byte) 0xff, 0, + // source address: + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + // destination address: + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + 0, 0, 0, 0, 0, 0, 0, 0, + // source and destination port: + -1, -1, -1, -1, + // padding to multiple of 16B: + 0, 0, 0, 0, 0, 0 + }; + + if (isL2) { + expectedMask[12] = (byte) 0xff; + expectedMask[13] = (byte) 0xff; + } + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, vlanTags == 2 ? 80 : 64, request.mask, vlanTags * VLAN_TAG_LEN); + } + + private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex, + final int vlanTags, final boolean isL2) { + assertEquals(1, request.isAdd); + assertEquals(tableIndex, request.tableIndex); + assertEquals(0, request.hitNextIndex); + + byte[] expectedMatch = new byte[] { + // L2: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // dscp(11), flow(123): + (byte) 0x02, (byte) 0xc0, (byte) 0x00, (byte) 0x7b, + // protocol (132): + 0, 0, (byte) 132, 0, + // source address: + (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x85, (byte) 0xa3, (byte) 0x08, (byte) 0xd3, + (byte) 0x13, (byte) 0x19, (byte) 0x8a, (byte) 0x2e, (byte) 0x03, (byte) 0x70, (byte) 0x73, (byte) 0x48, + // destination address: + (byte) 0xfe, (byte) 0x80, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0xab, (byte) 0xcd, + 0, 0, 0, 0, 0, 0, 0, 0, + // source and destination port: + 0x11, 0x11, 0x22, 0x22, + // padding to multiple of 16B: + 0, 0, 0, 0, 0, 0 + }; + + if (isL2) { + expectedMatch[12] = (byte) 0x86; + expectedMatch[13] = (byte) 0xdd; + } + AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, vlanTags == 2 ? 80 : 64, request.match, vlanTags * VLAN_TAG_LEN); + + } + + @Test + public void testCreateTable() { + final int nextTableIndex = 42; + final ClassifyAddDelTable request = + writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, 0); + verifyTableRequest(request, nextTableIndex, 0, false); + } + + @Test + public void testCreateTableForL2Interface() { + final int nextTableIndex = 42; + final ClassifyAddDelTable request = + writer.createTable(aceIp, InterfaceMode.L2, nextTableIndex, 0); + verifyTableRequest(request, nextTableIndex, 0, true); + } + + @Test + public void testCreateTable1VlanTag() { + final int nextTableIndex = 42; + final int vlanTags = 1; + final ClassifyAddDelTable request = + writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); + verifyTableRequest(request, nextTableIndex, vlanTags, false); + } + + @Test + public void testCreateTable2VlanTags() { + final int nextTableIndex = 42; + final int vlanTags = 2; + final ClassifyAddDelTable request = + writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); + verifyTableRequest(request, nextTableIndex, vlanTags, false); + } + + @Test + public void testCreateClassifySession() { + final int tableIndex = 123; + final ClassifyAddDelSession request = + writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0).get(0); + verifySessionRequest(request, tableIndex, 0, false); + } + + @Test + public void testCreateClassifySessionForL2Interface() { + final int tableIndex = 123; + final ClassifyAddDelSession request = + writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0).get(0); + verifySessionRequest(request, tableIndex, 0, true); + } + + @Test + public void testCreateClassifySession1VlanTag() { + final int tableIndex = 123; + final int vlanTags = 1; + final ClassifyAddDelSession request = + writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); + verifySessionRequest(request, tableIndex, vlanTags, false); + } + + @Test + public void testCreateClassifySession2VlanTags() { + final int tableIndex = 123; + final int vlanTags = 2; + final ClassifyAddDelSession request = + writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); + verifySessionRequest(request, tableIndex, vlanTags, false); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriterTest.java new file mode 100644 index 000000000..d224a067f --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpAndEthWriterTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.mockito.MockitoAnnotations.initMocks; + +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; +import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; +import org.junit.Before; +import org.junit.Test; +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.DenyBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; +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.DestinationPortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; +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.AceIpAndEth; +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.AceIpAndEthBuilder; +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.ace.ip.and.eth.ace.ip.version.AceIpv4Builder; + +public class AceIpAndEthWriterTest { + + private AceIpAndEthWriter writer; + private PacketHandling action; + private AceIpAndEth ace; + + @Before + public void setUp() { + initMocks(this); + writer = new AceIpAndEthWriter(); + action = new DenyBuilder().setDeny(true).build(); + ace = new AceIpAndEthBuilder() + .setDestinationMacAddress(new MacAddress("11:22:33:44:55:66")) + .setSourceMacAddress(new MacAddress("aa:bb:cc:dd:ee:ff")) + .setAceIpVersion(new AceIpv4Builder() + .setSourceIpv4Network(new Ipv4Prefix("1.2.3.4/32")).build()) + .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) + .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) + .build(); + } + + @Test + public void testCreateTable() { + final int nextTableIndex = 42; + final ClassifyAddDelTable request = writer.createTable(ace, InterfaceMode.L2, nextTableIndex, 0); + + assertEquals(1, request.isAdd); + assertEquals(-1, request.tableIndex); + assertEquals(1, request.nbuckets); + assertEquals(nextTableIndex, request.nextTableIndex); + assertEquals(0, request.skipNVectors); + assertEquals(3, request.matchNVectors); + assertEquals(AceEthWriter.TABLE_MEM_SIZE, request.memorySize); + + byte[] expectedMask = new byte[] { + // destination MAC: + -1, -1, -1, -1, -1, -1, + // source MAC: + -1, -1, -1, -1, -1, -1, + // ether type: + -1, -1, + // IP header + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // source address: + -1, -1, -1, -1, + // destination address: + 0, 0, 0, 0, + // source and destination port: + -1, -1, -1, -1, + // padding: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assertArrayEquals(expectedMask, request.mask); + } + + @Test + public void testCreateClassifySession() { + final int tableIndex = 123; + final ClassifyAddDelSession request = writer.createSession(action, ace, InterfaceMode.L2, tableIndex, 0).get(0); + + assertEquals(1, request.isAdd); + assertEquals(tableIndex, request.tableIndex); + assertEquals(0, request.hitNextIndex); + + byte[] expectedMatch = new byte[] { + // destination MAC: + (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, + // source MAC: + (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, + // ether type (IP4): + 0x08, 0, + // IP header + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + // source address: + 1, 2, 3, 4, + // destination address: + 0, 0, 0, 0, + // source and destination port: + 0x11, 0x11, 0x22, 0x22, + // padding: + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + assertArrayEquals(expectedMatch, request.match); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpWriterTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpWriterTestUtils.java new file mode 100644 index 000000000..59e22a87b --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/AceIpWriterTestUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static org.junit.Assert.assertArrayEquals; + +final class AceIpWriterTestUtils { + + private AceIpWriterTestUtils() { + throw new UnsupportedOperationException("This utility class cannot be instantiated"); + } + + protected static void assertArrayEqualsWithOffset(final byte[] baseExpected, final int expectedLength, final byte[] actual, + final int offset) { + byte[] expected = new byte[expectedLength]; + System.arraycopy(baseExpected, 0, expected, offset, Math.min(baseExpected.length, expectedLength-offset)); + + assertArrayEquals(expected, actual); + } +} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPairTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPairTest.java new file mode 100644 index 000000000..2127fb0fa --- /dev/null +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/common/PortPairTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.honeycomb.translate.v3po.interfaces.acl.common; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.hasSize; + +import java.util.List; +import org.junit.Test; +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.DestinationPortRangeBuilder; +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.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; + +public class PortPairTest { + + @Test + public void testSingleSrc() { + final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(123)).build(); + final List portPairs = PortPair.fromRange(src, null); + assertThat(portPairs, hasSize(1)); + assertThat(portPairs, contains(new PortPair(123, null))); + } + + @Test + public void testSrcRange() { + final SourcePortRange src = new SourcePortRangeBuilder() + .setLowerPort(new PortNumber(123)) + .setUpperPort(new PortNumber(125)).build(); + final List portPairs = PortPair.fromRange(src, null); + assertThat(portPairs, hasSize(3)); + assertThat(portPairs, contains(new PortPair(123, null), new PortPair(124, null), new PortPair(125, null))); + } + + @Test + public void testSrcRangeWithDst() { + final SourcePortRange src = new SourcePortRangeBuilder() + .setLowerPort(new PortNumber(123)) + .setUpperPort(new PortNumber(125)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(111)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(3)); + assertThat(portPairs, contains(new PortPair(123, 111), new PortPair(124, 111), new PortPair(125, 111))); + } + + @Test + public void testSingleDst() { + final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(123)).build(); + final List portPairs = PortPair.fromRange(null, dst); + assertThat(portPairs, hasSize(1)); + assertThat(portPairs, contains(new PortPair(null, 123))); + } + + @Test + public void testDstRange() { + final DestinationPortRange dst = new DestinationPortRangeBuilder() + .setLowerPort(new PortNumber(10)) + .setUpperPort(new PortNumber(11)).build(); + final List portPairs = PortPair.fromRange(null, dst); + assertThat(portPairs, hasSize(2)); + assertThat(portPairs, contains(new PortPair(null, 10), new PortPair(null, 11))); + } + + @Test + public void testDstRangeWithSrc() { + final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(111)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder() + .setLowerPort(new PortNumber(10)) + .setUpperPort(new PortNumber(11)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(2)); + assertThat(portPairs, contains(new PortPair(111, 10), new PortPair(111, 11))); + } + + @Test + public void testSinglePair() { + final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(123)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(321)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(1)); + assertThat(portPairs, contains(new PortPair(123, 321))); + } + + @Test + public void testCartesianProduct() { + final SourcePortRange src = new SourcePortRangeBuilder() + .setLowerPort(new PortNumber(1)) + .setUpperPort(new PortNumber(2)).build(); + final DestinationPortRange dst = new DestinationPortRangeBuilder() + .setLowerPort(new PortNumber(1)) + .setUpperPort(new PortNumber(3)).build(); + final List portPairs = PortPair.fromRange(src, dst); + assertThat(portPairs, hasSize(6)); + assertThat(portPairs, + contains(new PortPair(1, 1), new PortPair(1, 2), new PortPair(1, 3), new PortPair(2, 1), new PortPair(2, 2), + new PortPair(2, 3))); + } +} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java deleted file mode 100644 index cfff1e81c..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriterTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import org.junit.Before; -import org.junit.Test; -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.DenyBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEth; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceEthBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; - -public class AceEthWriterTest { - - private AceEthWriter writer; - private PacketHandling action; - private AceEth aceEth; - - @Before - public void setUp() { - initMocks(this); - writer = new AceEthWriter(); - action = new DenyBuilder().setDeny(true).build(); - aceEth = new AceEthBuilder() - .setDestinationMacAddress(new MacAddress("11:22:33:44:55:66")) - .setDestinationMacAddressMask(new MacAddress("ff:ff:ff:ff:ff:ff")) - .setSourceMacAddress(new MacAddress("aa:bb:cc:dd:ee:ff")) - .setSourceMacAddressMask(new MacAddress("ff:ff:ff:00:00:00")) - .build(); - } - - @Test - public void testCreateTable() { - final int nextTableIndex = 42; - final ClassifyAddDelTable request = writer.createTable(aceEth, InterfaceMode.L2, nextTableIndex, 0); - - assertEquals(1, request.isAdd); - assertEquals(-1, request.tableIndex); - assertEquals(1, request.nbuckets); - assertEquals(nextTableIndex, request.nextTableIndex); - assertEquals(0, request.skipNVectors); - assertEquals(AceEthWriter.MATCH_N_VECTORS, request.matchNVectors); - assertEquals(AceEthWriter.TABLE_MEM_SIZE, request.memorySize); - - byte[] expectedMask = new byte[] { - // destination MAC: - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - // source MAC: - (byte) 0xff, (byte) 0xff, (byte) 0xff, 0, 0, 0, - 0, 0, 0, 0 - }; - assertArrayEquals(expectedMask, request.mask); - } - - @Test - public void testCreateClassifySession() { - final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, aceEth, InterfaceMode.L2, tableIndex, 0).get(0); - - assertEquals(1, request.isAdd); - assertEquals(tableIndex, request.tableIndex); - assertEquals(0, request.hitNextIndex); - - byte[] expectedMatch = new byte[] { - // destination MAC: - (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, - // source MAC: - (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, - 0, 0, 0, 0 - }; - assertArrayEquals(expectedMatch, request.match); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java deleted file mode 100644 index 948e5f95b..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4WriterTest.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.AclTranslator.VLAN_TAG_LEN; -import static org.junit.Assert.assertEquals; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import org.junit.Before; -import org.junit.Test; -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.DenyBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -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.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; - -public class AceIp4WriterTest { - - private AceIp4Writer writer; - private PacketHandling action; - private AceIp aceIp; - - @Before - public void setUp() throws Exception { - initMocks(this); - writer = new AceIp4Writer(); - action = new DenyBuilder().setDeny(true).build(); - aceIp = new AceIpBuilder() - .setProtocol((short) 132) - .setDscp(new Dscp((short) 11)) - .setAceIpVersion(new AceIpv4Builder() - .setSourceIpv4Network(new Ipv4Prefix("1.2.3.4/32")) - .setDestinationIpv4Network(new Ipv4Prefix("1.2.4.5/24")) - .build()) - .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) - .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) - .build(); - } - - private static void verifyTableRequest(final ClassifyAddDelTable request, final int nextTableIndex, - final int vlanTags, final boolean isL2) { - assertEquals(1, request.isAdd); - assertEquals(-1, request.tableIndex); - assertEquals(1, request.nbuckets); - assertEquals(nextTableIndex, request.nextTableIndex); - assertEquals(0, request.skipNVectors); - assertEquals(AceIp4Writer.MATCH_N_VECTORS, request.matchNVectors); - assertEquals(AceIp4Writer.TABLE_MEM_SIZE, request.memorySize); - - byte[] expectedMask = new byte[] { - // L2: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // dscp: - (byte) 0x00, (byte) 0xfc, - // protocol: - 0, 0, 0, 0, 0, 0, 0, (byte) 0xff, 0, 0, - // source address: - -1, -1, -1, -1, - // destination address: - -1, -1, -1, 0, - // source and destination port: - -1, -1, -1, -1, - // padding: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - if (isL2) { - expectedMask[12] = (byte) 0xff; - expectedMask[13] = (byte) 0xff; - } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, expectedMask.length, request.mask, vlanTags * VLAN_TAG_LEN); - - } - - private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex, - final int vlanTags, final boolean isL2) { - assertEquals(1, request.isAdd); - assertEquals(tableIndex, request.tableIndex); - assertEquals(0, request.hitNextIndex); - - byte[] expectedMatch = new byte[] { - // L2: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // dscp: - 0, (byte) 0x2c, - // protocol (132): - 0, 0, 0, 0, 0, 0, 0, (byte) 132, 0, 0, - // source address: - 1, 2, 3, 4, - // destination address: - 1, 2, 4, 0, - // source and destination port: - 0x11, 0x11, 0x22, 0x22, - // padding: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - if (isL2) { - expectedMatch[12] = (byte) 0x08; - expectedMatch[13] = (byte) 0x00; - } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, expectedMatch.length, request.match, vlanTags * VLAN_TAG_LEN); - - } - - @Test - public void testCreateTable() throws Exception { - final int nextTableIndex = 42; - final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, 0); - verifyTableRequest(request, nextTableIndex, 0, false); - } - - @Test - public void testCreateTableForL2Interface() throws Exception { - final int nextTableIndex = 42; - final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L2, nextTableIndex, 0); - verifyTableRequest(request, nextTableIndex, 0, true); - } - - @Test - public void testCreateTable1VlanTag() throws Exception { - final int nextTableIndex = 42; - final int vlanTags = 1; - final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); - verifyTableRequest(request, nextTableIndex, vlanTags, false); - } - - @Test - public void testCreateTable2VlanTags() throws Exception { - final int nextTableIndex = 42; - final int vlanTags = 2; - final ClassifyAddDelTable request = writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); - verifyTableRequest(request, nextTableIndex, vlanTags, false); - } - - @Test - public void testCreateClassifySession() throws Exception { - final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0).get(0); - verifySessionRequest(request, tableIndex, 0, false); - } - - @Test - public void testCreateClassifySessionForL2Interface() throws Exception { - final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0).get(0); - verifySessionRequest(request, tableIndex, 0, true); - } - - @Test - public void testCreateClassifySession1VlanTag() throws Exception { - final int tableIndex = 123; - final int vlanTags = 1; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); - verifySessionRequest(request, tableIndex, vlanTags, false); - } - - @Test - public void testCreateClassifySession2VlanTags() throws Exception { - final int tableIndex = 123; - final int vlanTags = 2; - final ClassifyAddDelSession request = writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); - - verifySessionRequest(request, tableIndex, vlanTags, false); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java deleted file mode 100644 index b45fb418c..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6WriterTest.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.AclTranslator.VLAN_TAG_LEN; -import static org.junit.Assert.assertEquals; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import org.junit.Before; -import org.junit.Test; -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.DenyBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6Builder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Dscp; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6FlowLabel; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix; -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.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; - -public class AceIp6WriterTest { - - private AceIp6Writer writer; - private PacketHandling action; - private AceIp aceIp; - - @Before - public void setUp() { - initMocks(this); - writer = new AceIp6Writer(); - action = new DenyBuilder().setDeny(true).build(); - aceIp = new AceIpBuilder() - .setProtocol((short) 132) - .setDscp(new Dscp((short) 11)) - .setAceIpVersion(new AceIpv6Builder() - .setFlowLabel(new Ipv6FlowLabel(123L)) - .setSourceIpv6Network(new Ipv6Prefix("2001:db8:85a3:8d3:1319:8a2e:370:7348/128")) - .setDestinationIpv6Network(new Ipv6Prefix("fe80:1234:5678:abcd:ef01::/64")) - .build()) - .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) - .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) - .build(); - } - - - private static void verifyTableRequest(final ClassifyAddDelTable request, final int nextTableIndex, - final int vlanTags, final boolean isL2) { - assertEquals(1, request.isAdd); - assertEquals(-1, request.tableIndex); - assertEquals(1, request.nbuckets); - assertEquals(nextTableIndex, request.nextTableIndex); - assertEquals(0, request.skipNVectors); - assertEquals(vlanTags == 2 ? 5 : 4, request.matchNVectors); - assertEquals(AceIp6Writer.TABLE_MEM_SIZE, request.memorySize); - - byte[] expectedMask = new byte[] { - // L2: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // dscp, flow: - (byte) 0x0f, (byte) 0xcf, (byte) 0xff, (byte) 0xff, - // protocol: - 0, 0, (byte) 0xff, 0, - // source address: - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - // destination address: - (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, - 0, 0, 0, 0, 0, 0, 0, 0, - // source and destination port: - -1, -1, -1, -1, - // padding to multiple of 16B: - 0, 0, 0, 0, 0, 0 - }; - - if (isL2) { - expectedMask[12] = (byte) 0xff; - expectedMask[13] = (byte) 0xff; - } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMask, vlanTags == 2 ? 80 : 64, request.mask, vlanTags * VLAN_TAG_LEN); - } - - private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex, - final int vlanTags, final boolean isL2) { - assertEquals(1, request.isAdd); - assertEquals(tableIndex, request.tableIndex); - assertEquals(0, request.hitNextIndex); - - byte[] expectedMatch = new byte[] { - // L2: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // dscp(11), flow(123): - (byte) 0x02, (byte) 0xc0, (byte) 0x00, (byte) 0x7b, - // protocol (132): - 0, 0, (byte) 132, 0, - // source address: - (byte) 0x20, (byte) 0x01, (byte) 0x0d, (byte) 0xb8, (byte) 0x85, (byte) 0xa3, (byte) 0x08, (byte) 0xd3, - (byte) 0x13, (byte) 0x19, (byte) 0x8a, (byte) 0x2e, (byte) 0x03, (byte) 0x70, (byte) 0x73, (byte) 0x48, - // destination address: - (byte) 0xfe, (byte) 0x80, (byte) 0x12, (byte) 0x34, (byte) 0x56, (byte) 0x78, (byte) 0xab, (byte) 0xcd, - 0, 0, 0, 0, 0, 0, 0, 0, - // source and destination port: - 0x11, 0x11, 0x22, 0x22, - // padding to multiple of 16B: - 0, 0, 0, 0, 0, 0 - }; - - if (isL2) { - expectedMatch[12] = (byte) 0x86; - expectedMatch[13] = (byte) 0xdd; - } - AceIpWriterTestUtils.assertArrayEqualsWithOffset(expectedMatch, vlanTags == 2 ? 80 : 64, request.match, vlanTags * VLAN_TAG_LEN); - - } - - @Test - public void testCreateTable() { - final int nextTableIndex = 42; - final ClassifyAddDelTable request = - writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, 0); - verifyTableRequest(request, nextTableIndex, 0, false); - } - - @Test - public void testCreateTableForL2Interface() { - final int nextTableIndex = 42; - final ClassifyAddDelTable request = - writer.createTable(aceIp, InterfaceMode.L2, nextTableIndex, 0); - verifyTableRequest(request, nextTableIndex, 0, true); - } - - @Test - public void testCreateTable1VlanTag() { - final int nextTableIndex = 42; - final int vlanTags = 1; - final ClassifyAddDelTable request = - writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); - verifyTableRequest(request, nextTableIndex, vlanTags, false); - } - - @Test - public void testCreateTable2VlanTags() { - final int nextTableIndex = 42; - final int vlanTags = 2; - final ClassifyAddDelTable request = - writer.createTable(aceIp, InterfaceMode.L3, nextTableIndex, vlanTags); - verifyTableRequest(request, nextTableIndex, vlanTags, false); - } - - @Test - public void testCreateClassifySession() { - final int tableIndex = 123; - final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, 0).get(0); - verifySessionRequest(request, tableIndex, 0, false); - } - - @Test - public void testCreateClassifySessionForL2Interface() { - final int tableIndex = 123; - final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L2, tableIndex, 0).get(0); - verifySessionRequest(request, tableIndex, 0, true); - } - - @Test - public void testCreateClassifySession1VlanTag() { - final int tableIndex = 123; - final int vlanTags = 1; - final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); - verifySessionRequest(request, tableIndex, vlanTags, false); - } - - @Test - public void testCreateClassifySession2VlanTags() { - final int tableIndex = 123; - final int vlanTags = 2; - final ClassifyAddDelSession request = - writer.createSession(action, aceIp, InterfaceMode.L3, tableIndex, vlanTags).get(0); - verifySessionRequest(request, tableIndex, vlanTags, false); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java deleted file mode 100644 index 7739f0f7f..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriterTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.mockito.MockitoAnnotations.initMocks; - -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession; -import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable; -import org.junit.Before; -import org.junit.Test; -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.DenyBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix; -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.DestinationPortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; -import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress; -import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode; -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.AceIpAndEth; -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.AceIpAndEthBuilder; -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.ace.ip.and.eth.ace.ip.version.AceIpv4Builder; - -public class AceIpAndEthWriterTest { - - private AceIpAndEthWriter writer; - private PacketHandling action; - private AceIpAndEth ace; - - @Before - public void setUp() { - initMocks(this); - writer = new AceIpAndEthWriter(); - action = new DenyBuilder().setDeny(true).build(); - ace = new AceIpAndEthBuilder() - .setDestinationMacAddress(new MacAddress("11:22:33:44:55:66")) - .setSourceMacAddress(new MacAddress("aa:bb:cc:dd:ee:ff")) - .setAceIpVersion(new AceIpv4Builder() - .setSourceIpv4Network(new Ipv4Prefix("1.2.3.4/32")).build()) - .setSourcePortRange(new SourcePortRangeBuilder().setLowerPort(new PortNumber(0x1111)).build()) - .setDestinationPortRange(new DestinationPortRangeBuilder().setLowerPort(new PortNumber(0x2222)).build()) - .build(); - } - - @Test - public void testCreateTable() { - final int nextTableIndex = 42; - final ClassifyAddDelTable request = writer.createTable(ace, InterfaceMode.L2, nextTableIndex, 0); - - assertEquals(1, request.isAdd); - assertEquals(-1, request.tableIndex); - assertEquals(1, request.nbuckets); - assertEquals(nextTableIndex, request.nextTableIndex); - assertEquals(0, request.skipNVectors); - assertEquals(3, request.matchNVectors); - assertEquals(AceEthWriter.TABLE_MEM_SIZE, request.memorySize); - - byte[] expectedMask = new byte[] { - // destination MAC: - -1, -1, -1, -1, -1, -1, - // source MAC: - -1, -1, -1, -1, -1, -1, - // ether type: - -1, -1, - // IP header - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // source address: - -1, -1, -1, -1, - // destination address: - 0, 0, 0, 0, - // source and destination port: - -1, -1, -1, -1, - // padding: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - assertArrayEquals(expectedMask, request.mask); - } - - @Test - public void testCreateClassifySession() { - final int tableIndex = 123; - final ClassifyAddDelSession request = writer.createSession(action, ace, InterfaceMode.L2, tableIndex, 0).get(0); - - assertEquals(1, request.isAdd); - assertEquals(tableIndex, request.tableIndex); - assertEquals(0, request.hitNextIndex); - - byte[] expectedMatch = new byte[] { - // destination MAC: - (byte) 0x11, (byte) 0x22, (byte) 0x33, (byte) 0x44, (byte) 0x55, (byte) 0x66, - // source MAC: - (byte) 0xaa, (byte) 0xbb, (byte) 0xcc, (byte) 0xdd, (byte) 0xee, (byte) 0xff, - // ether type (IP4): - 0x08, 0, - // IP header - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - // source address: - 1, 2, 3, 4, - // destination address: - 0, 0, 0, 0, - // source and destination port: - 0x11, 0x11, 0x22, 0x22, - // padding: - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - assertArrayEquals(expectedMatch, request.match); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java deleted file mode 100644 index e7e29916c..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpWriterTestUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static org.junit.Assert.assertArrayEquals; - -final class AceIpWriterTestUtils { - - private AceIpWriterTestUtils() { - throw new UnsupportedOperationException("This utility class cannot be instantiated"); - } - - protected static void assertArrayEqualsWithOffset(final byte[] baseExpected, final int expectedLength, final byte[] actual, - final int offset) { - byte[] expected = new byte[expectedLength]; - System.arraycopy(baseExpected, 0, expected, offset, Math.min(baseExpected.length, expectedLength-offset)); - - assertArrayEquals(expected, actual); - } -} diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizerTest.java index 6c7eea8b1..bae706262 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizerTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizerTest.java @@ -84,7 +84,7 @@ public class IetfAclCustomizerTest extends WriterCustomizerTest { @Override protected void setUp() { - customizer = new IetfAclCustomizer(new IetfAclWriter(api), new NamingContext("prefix", IFC_TEST_INSTANCE)); + customizer = new IetfAclCustomizer(new IngressIetfAclWriter(api), new NamingContext("prefix", IFC_TEST_INSTANCE)); defineMapping(mappingContext, IF_NAME, IF_INDEX, IFC_TEST_INSTANCE); acl = new IngressBuilder().setAccessLists( new AccessListsBuilder().setAcl( diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java deleted file mode 100644 index b02c411ff..000000000 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/PortPairTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2016 Cisco and/or its affiliates. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.hasSize; - -import java.util.List; -import org.junit.Test; -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.DestinationPortRangeBuilder; -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.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.acl.transport.header.fields.SourcePortRangeBuilder; - -public class PortPairTest { - - @Test - public void testSingleSrc() { - final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(123)).build(); - final List portPairs = PortPair.fromRange(src, null); - assertThat(portPairs, hasSize(1)); - assertThat(portPairs, contains(new PortPair(123, null))); - } - - @Test - public void testSrcRange() { - final SourcePortRange src = new SourcePortRangeBuilder() - .setLowerPort(new PortNumber(123)) - .setUpperPort(new PortNumber(125)).build(); - final List portPairs = PortPair.fromRange(src, null); - assertThat(portPairs, hasSize(3)); - assertThat(portPairs, contains(new PortPair(123, null), new PortPair(124, null), new PortPair(125, null))); - } - - @Test - public void testSrcRangeWithDst() { - final SourcePortRange src = new SourcePortRangeBuilder() - .setLowerPort(new PortNumber(123)) - .setUpperPort(new PortNumber(125)).build(); - final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(111)).build(); - final List portPairs = PortPair.fromRange(src, dst); - assertThat(portPairs, hasSize(3)); - assertThat(portPairs, contains(new PortPair(123, 111), new PortPair(124, 111), new PortPair(125, 111))); - } - - @Test - public void testSingleDst() { - final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(123)).build(); - final List portPairs = PortPair.fromRange(null, dst); - assertThat(portPairs, hasSize(1)); - assertThat(portPairs, contains(new PortPair(null, 123))); - } - - @Test - public void testDstRange() { - final DestinationPortRange dst = new DestinationPortRangeBuilder() - .setLowerPort(new PortNumber(10)) - .setUpperPort(new PortNumber(11)).build(); - final List portPairs = PortPair.fromRange(null, dst); - assertThat(portPairs, hasSize(2)); - assertThat(portPairs, contains(new PortPair(null, 10), new PortPair(null, 11))); - } - - @Test - public void testDstRangeWithSrc() { - final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(111)).build(); - final DestinationPortRange dst = new DestinationPortRangeBuilder() - .setLowerPort(new PortNumber(10)) - .setUpperPort(new PortNumber(11)).build(); - final List portPairs = PortPair.fromRange(src, dst); - assertThat(portPairs, hasSize(2)); - assertThat(portPairs, contains(new PortPair(111, 10), new PortPair(111, 11))); - } - - @Test - public void testSinglePair() { - final SourcePortRange src = new SourcePortRangeBuilder().setLowerPort(new PortNumber(123)).build(); - final DestinationPortRange dst = new DestinationPortRangeBuilder().setLowerPort(new PortNumber(321)).build(); - final List portPairs = PortPair.fromRange(src, dst); - assertThat(portPairs, hasSize(1)); - assertThat(portPairs, contains(new PortPair(123, 321))); - } - - @Test - public void testCartesianProduct() { - final SourcePortRange src = new SourcePortRangeBuilder() - .setLowerPort(new PortNumber(1)) - .setUpperPort(new PortNumber(2)).build(); - final DestinationPortRange dst = new DestinationPortRangeBuilder() - .setLowerPort(new PortNumber(1)) - .setUpperPort(new PortNumber(3)).build(); - final List portPairs = PortPair.fromRange(src, dst); - assertThat(portPairs, hasSize(6)); - assertThat(portPairs, - contains(new PortPair(1, 1), new PortPair(1, 2), new PortPair(1, 3), new PortPair(2, 1), new PortPair(2, 2), - new PortPair(2, 3))); - } -} \ No newline at end of file diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizerTest.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizerTest.java index 76c681ca9..ddf3206b9 100644 --- a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizerTest.java +++ b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizerTest.java @@ -70,7 +70,7 @@ public class SubInterfaceIetfAclCustomizerTest extends WriterCustomizerTest { @Override protected void setUp() { customizer = - new SubInterfaceIetfAclCustomizer(new IetfAclWriter(api), new NamingContext("prefix", IFC_TEST_INSTANCE)); + new SubInterfaceIetfAclCustomizer(new IngressIetfAclWriter(api), new NamingContext("prefix", IFC_TEST_INSTANCE)); defineMapping(mappingContext, IF_NAME, IF_INDEX, IFC_TEST_INSTANCE); acl = new IngressBuilder().setAccessLists( -- cgit 1.2.3-korg