summaryrefslogtreecommitdiffstats
path: root/v3po/v3po2vpp/src/main/java
diff options
context:
space:
mode:
authorMarek Gradzki <mgradzki@cisco.com>2016-10-10 14:55:15 +0200
committerMaros Marsalek <mmarsale@cisco.com>2016-10-13 11:27:29 +0000
commita55da7924adda3e82f6e5be40e01084c65e93ac0 (patch)
treeee9d6f6ff1144186c0e13e111ac35b435fb9ad75 /v3po/v3po2vpp/src/main/java
parent5543d61420bd198dc34e8f0e64c3479c185a9c2b (diff)
HONEYCOMB-233: add support for mixing L2/L3 rules
In case of L2 interfaces, acls are translated into a chain of classify tables and assigned as L2 table. In case of L3 interfaces, acls are translated into ip4 and ip6 chains (eth only rules go to both chains, rest - depending on ip-version). Limitations: - it is not possible to define L3 rule without specifying ip-version (common header fields for IP4/IP6 have different offsets), - eth rules on L3 interfaces are applied only to IP traffic (vpp classfier limitation). Change-Id: I7ca2648cabad8c6e936cf71a51e06596a42891e8 Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
Diffstat (limited to 'v3po/v3po2vpp/src/main/java')
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/IetfAClWriterProvider.java8
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/InterfacesWriterFactory.java6
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/SubinterfaceAugmentationWriterFactory.java6
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/V3poModule.java4
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/IetfAclCustomizer.java6
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java6
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AbstractAceWriter.java190
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriter.java116
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp4Writer.java158
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIp6Writer.java191
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriter.java120
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceWriter.java46
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AclTranslator.java64
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclCustomizer.java4
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAclWriter.java (renamed from v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/IetfAClWriter.java)179
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip4AclTranslator.java135
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip6AclTranslator.java169
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/L2AclTranslator.java90
-rw-r--r--v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java4
19 files changed, 820 insertions, 682 deletions
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
index 8e001b75d..301c30501 100644
--- 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
@@ -18,10 +18,10 @@ 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.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclWriter;
import io.fd.vpp.jvpp.core.future.FutureJVppCore;
-class IetfAClWriterProvider implements Provider<IetfAClWriter> {
+class IetfAClWriterProvider implements Provider<IetfAclWriter> {
private final FutureJVppCore jvpp;
@@ -31,7 +31,7 @@ class IetfAClWriterProvider implements Provider<IetfAClWriter> {
}
@Override
- public IetfAClWriter get() {
- return new IetfAClWriter(jvpp);
+ public IetfAclWriter get() {
+ return new IetfAclWriter(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 9c46ba316..be3801bd2 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
@@ -35,7 +35,7 @@ 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.IetfAclWriter;
import io.fd.honeycomb.translate.v3po.interfaces.acl.ingress.IetfAclCustomizer;
import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4AddressCustomizer;
import io.fd.honeycomb.translate.v3po.interfaces.ip.Ipv4Customizer;
@@ -94,7 +94,7 @@ 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 IetfAclWriter aclWriter;
private final NamingContext bdNamingContext;
private final NamingContext ifcNamingContext;
private final VppClassifierContextManager classifyTableContext;
@@ -102,7 +102,7 @@ public final class InterfacesWriterFactory implements WriterFactory {
@Inject
public InterfacesWriterFactory(final FutureJVppCore vppJvppIfcDependency,
- final IetfAClWriter aclWriter,
+ final IetfAclWriter aclWriter,
@Named("bridge-domain-context") final NamingContext bridgeDomainContextDependency,
@Named("interface-context") final NamingContext interfaceContextDependency,
@Named("classify-table-context") final VppClassifierContextManager classifyTableContext,
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 f4dc07646..afa362d5c 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
@@ -26,7 +26,7 @@ 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.ingress.IetfAclWriter;
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;
@@ -59,7 +59,7 @@ import io.fd.vpp.jvpp.core.future.FutureJVppCore;
public final class SubinterfaceAugmentationWriterFactory implements WriterFactory {
private final FutureJVppCore jvpp;
- private final IetfAClWriter aclWriter;
+ private final IetfAclWriter aclWriter;
private final NamingContext ifcContext;
private final NamingContext bdContext;
private final VppClassifierContextManager classifyTableContext;
@@ -79,7 +79,7 @@ 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 IetfAclWriter aclWriter,
final NamingContext ifcContext, final NamingContext bdContext, final VppClassifierContextManager classifyTableContext) {
this.jvpp = jvpp;
this.aclWriter = aclWriter;
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 de29d5d2c..eaecdf025 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,7 +26,7 @@ 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.ingress.IetfAclWriter;
import io.fd.honeycomb.translate.v3po.notification.InterfaceChangeNotificationProducer;
import io.fd.honeycomb.translate.vpp.util.NamingContext;
import io.fd.honeycomb.translate.v3po.vppclassifier.VppClassifierContextManager;
@@ -59,7 +59,7 @@ public class V3poModule extends AbstractModule {
bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(1));
// Utils
- bind(IetfAClWriter.class).toProvider(IetfAClWriterProvider.class);
+ bind(IetfAclWriter.class).toProvider(IetfAClWriterProvider.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/egress/IetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/IetfAclCustomizer.java
index 0eff83b00..3dc9e2262 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
@@ -19,7 +19,7 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl.egress;
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.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;
@@ -31,11 +31,11 @@ import org.slf4j.LoggerFactory;
public class IetfAclCustomizer implements WriterCustomizer<Egress> {
private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class);
- private final IetfAClWriter aclWriter;
+ private final IetfAclWriter aclWriter;
private final NamingContext interfaceContext;
- public IetfAclCustomizer(final IetfAClWriter aclWriter, final NamingContext interfaceContext) {
+ public IetfAclCustomizer(final IetfAclWriter aclWriter, 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/egress/SubInterfaceIetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/egress/SubInterfaceIetfAclCustomizer.java
index 2a20a754f..b5198465a 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
@@ -19,7 +19,7 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl.egress;
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.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;
@@ -31,10 +31,10 @@ import org.slf4j.LoggerFactory;
public class SubInterfaceIetfAclCustomizer implements WriterCustomizer<Egress> {
private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class);
- private final IetfAClWriter aclWriter;
+ private final IetfAclWriter aclWriter;
private final NamingContext interfaceContext;
- public SubInterfaceIetfAclCustomizer(final IetfAClWriter aclWriter, final NamingContext interfaceContext) {
+ public SubInterfaceIetfAclCustomizer(final IetfAclWriter aclWriter, 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/AbstractAceWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AbstractAceWriter.java
deleted file mode 100644
index a5bbab545..000000000
--- a/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AbstractAceWriter.java
+++ /dev/null
@@ -1,190 +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 static com.google.common.base.Preconditions.checkNotNull;
-
-import com.google.common.annotations.VisibleForTesting;
-import io.fd.honeycomb.translate.vpp.util.JvppReplyConsumer;
-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.InputAclSetInterface;
-import io.fd.vpp.jvpp.core.future.FutureJVppCore;
-import java.util.List;
-import java.util.ListIterator;
-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.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;
-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.ietf.acl.base.attributes.AccessLists;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-/**
- * Base writer for translation of ietf-acl model ACEs to VPP's classify tables and sessions. <p/> Creates one classify
- * table with single session per ACE.
- *
- * @param <T> type of access control list entry
- */
-abstract class AbstractAceWriter<T extends AceType> implements AceWriter, JvppReplyConsumer {
-
- // 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 for now
- protected static final int TABLE_MEM_SIZE = 8 * 1024;
-
- @VisibleForTesting
- static final int VLAN_TAG_LEN = 4;
-
- private static final int PERMIT = -1;
- private static final int DENY = 0;
-
- private final FutureJVppCore futureJVppCore;
-
- public AbstractAceWriter(@Nonnull final FutureJVppCore futureJVppCore) {
- this.futureJVppCore = checkNotNull(futureJVppCore, "futureJVppCore should not be null");
- }
-
- /**
- * Creates classify table for given ACE.
- *
- * @param ace ACE to be translated
- * @param mode interface mode
- * @param nextTableIndex classify table index
- * @param vlanTags number of vlan tags
- * @return classify table that represents given ACE
- */
- protected abstract ClassifyAddDelTable createClassifyTable(@Nonnull final T ace,
- @Nullable final InterfaceMode mode,
- final int nextTableIndex,
- final int vlanTags);
-
- /**
- * Creates classify session for given ACE.
- *
- * @param action packet handling action (permit/deny)
- * @param ace ACE to be translated
- * @param mode interface mode
- * @param tableIndex classify table index for the given session
- * @param vlanTags number of vlan tags
- * @return classify session that represents given ACE
- */
- protected abstract ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
- @Nonnull final T ace,
- @Nullable final InterfaceMode mode,
- final int tableIndex,
- final int vlanTags);
-
- /**
- * Sets classify table index for input_acl_set_interface request.
- *
- * @param request request DTO
- * @param tableIndex pointer to a chain of classify tables
- */
- protected abstract void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex);
-
- @Override
- public final void write(@Nonnull final InstanceIdentifier<?> id, @Nonnull final List<Ace> aces,
- final InterfaceMode mode, final AccessLists.DefaultAction defaultAction,
- @Nonnull final InputAclSetInterface request,
- @Nonnegative final int vlanTags)
- throws WriteFailedException {
-
- checkArgument(vlanTags >= 0 && vlanTags <= 2, "Number of vlan tags %s is not in [0,2] range");
- int nextTableIndex = configureDefaltAction(id, defaultAction);
-
- final ListIterator<Ace> iterator = aces.listIterator(aces.size());
- while (iterator.hasPrevious()) {
- // Create table + session per entry
- final Ace ace = iterator.previous();
- final PacketHandling action = ace.getActions().getPacketHandling();
- final T type = (T)ace.getMatches().getAceType();
- final ClassifyAddDelTable ctRequest = createClassifyTable(type, mode, nextTableIndex, vlanTags);
- nextTableIndex = createClassifyTable(id, ctRequest);
- createClassifySession(id, createClassifySession(action, type, mode, nextTableIndex, vlanTags));
- }
- setClassifyTable(request, nextTableIndex);
- }
-
- private int configureDefaltAction(@Nonnull final InstanceIdentifier<?> id, final AccessLists.DefaultAction defaultAction)
- throws WriteFailedException {
- ClassifyAddDelTable ctRequest = createClassifyTable(-1);
- if (AccessLists.DefaultAction.Permit.equals(defaultAction)) {
- ctRequest.missNextIndex = PERMIT;
- } else {
- ctRequest.missNextIndex = DENY;
- }
- 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<ClassifyAddDelTableReply> cs = futureJVppCore.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<ClassifyAddDelSessionReply> cs = futureJVppCore.classifyAddDelSession(request);
-
- getReplyForWrite(cs.toCompletableFuture(), id);
- }
-
- protected ClassifyAddDelTable createClassifyTable(final int nextTableIndex) {
- final ClassifyAddDelTable request = new ClassifyAddDelTable();
- request.isAdd = 1;
- request.tableIndex = -1; // value not present
- request.nbuckets = 1; // we expect exactly one session per table
- request.nextTableIndex = nextTableIndex;
- request.memorySize = TABLE_MEM_SIZE;
- request.missNextIndex = -1; // value not set, but anyway it is ignored for tables in chain
- return request;
- }
-
- protected ClassifyAddDelSession createClassifySession(@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;
- }
-
- protected 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/AceEthWriter.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceEthWriter.java
index 939e4eb98..91ab927fb 100644
--- 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
@@ -16,15 +16,9 @@
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.honeycomb.translate.vpp.util.MacTranslator;
import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
-import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
-import io.fd.vpp.jvpp.core.future.FutureJVppCore;
-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;
@@ -33,69 +27,29 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-final class AceEthWriter extends AbstractAceWriter<AceEth> implements MacTranslator {
+final class AceEthWriter implements AceWriter<AceEth>, AclTranslator, L2AclTranslator {
@VisibleForTesting
static final int MATCH_N_VECTORS = 1;
private static final Logger LOG = LoggerFactory.getLogger(AceEthWriter.class);
- public AceEthWriter(@Nonnull final FutureJVppCore futureJVppCore) {
- super(futureJVppCore);
- }
-
- private static void checkInterfaceMode(@Nullable final InterfaceMode mode) {
- checkArgument(InterfaceMode.L2.equals(mode), "L2 rules are not allowed for interface in L3 mode");
- }
-
@Override
- public ClassifyAddDelTable createClassifyTable(@Nonnull final AceEth aceEth,
- @Nullable final InterfaceMode mode,
- final int nextTableIndex,
- final int vlanTags) {
- checkInterfaceMode(mode);
-
- final ClassifyAddDelTable request = createClassifyTable(nextTableIndex);
+ 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 = true;
-
- // 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 (aceEth.getDestinationMacAddressMask() != null) {
- aceIsEmpty = false;
- final String macAddress = aceEth.getDestinationMacAddressMask().getValue();
- final List<String> parts = COLON_SPLITTER.splitToList(macAddress);
- int i = 0;
- for (String part : parts) {
- request.mask[i++] = parseHexByte(part);
- }
- } else if (aceEth.getDestinationMacAddress() != null) {
- aceIsEmpty = false;
- for (int i = 0; i < 6; ++i) {
- request.mask[i] = (byte) 0xff;
- }
- }
-
- // 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 (aceEth.getSourceMacAddressMask() != null) {
- aceIsEmpty = false;
- final String macAddress = aceEth.getSourceMacAddressMask().getValue();
- final List<String> parts = COLON_SPLITTER.splitToList(macAddress);
- int i = 6;
- for (String part : parts) {
- request.mask[i++] = parseHexByte(part);
- }
- } else if (aceEth.getSourceMacAddress() != null) {
- aceIsEmpty = false;
- for (int i = 6; i < 12; ++i) {
- request.mask[i] = (byte) 0xff;
- }
- }
+ 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()));
+ String.format("Ace %s does not define packet field match values", aceEth.toString()));
}
request.skipNVectors = 0;
@@ -106,50 +60,24 @@ final class AceEthWriter extends AbstractAceWriter<AceEth> implements MacTransla
}
@Override
- public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
- @Nonnull final AceEth aceEth,
- @Nullable final InterfaceMode mode,
- final int tableIndex,
- final int vlanTags) {
- checkInterfaceMode(mode);
-
- final ClassifyAddDelSession request = createClassifySession(action, tableIndex);
+ public ClassifyAddDelSession 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 = true;
-
- if (aceEth.getDestinationMacAddress() != null) {
- noMatch = false;
- final String macAddress = aceEth.getDestinationMacAddress().getValue();
- final List<String> parts = COLON_SPLITTER.splitToList(macAddress);
- int i = 0;
- for (String part : parts) {
- request.match[i++] = parseHexByte(part);
- }
- }
-
- if (aceEth.getSourceMacAddress() != null) {
- noMatch = false;
- final String macAddress = aceEth.getSourceMacAddress().getValue();
- final List<String> parts = COLON_SPLITTER.splitToList(macAddress);
- int i = 6;
- for (String part : parts) {
- request.match[i++] = parseHexByte(part);
- }
- }
+ 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()));
+ 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 request;
}
-
- @Override
- protected void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex) {
- request.l2TableIndex = tableIndex;
- }
}
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
index 2f8d030ae..affc8735d 100644
--- 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
@@ -19,121 +19,42 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.VisibleForTesting;
-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 io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
-import io.fd.vpp.jvpp.core.future.FutureJVppCore;
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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
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 extends AbstractAceWriter<AceIp> implements Ipv4Translator {
+final class AceIp4Writer implements AceWriter<AceIp>, AclTranslator, Ip4AclTranslator {
@VisibleForTesting
static final int MATCH_N_VECTORS = 3; // number of 16B vectors
- private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class);
private static final int TABLE_MASK_LENGTH = 48;
- private static final int IP4_MASK_BIT_LENGTH = 32;
-
- private static final int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
- private static final int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET+2;
- private static final int DSCP_OFFSET = 15;
- private static final int DSCP_MASK = 0xfc;
- private static final int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET+9;
- private static final int IP_PROTOCOL_MASK = 0xff;
- private static final int IP4_LEN = 4;
- private static final int SRC_IP_OFFSET = IP_VERSION_OFFSET + 12;
- private static final int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN;
-
- public AceIp4Writer(@Nonnull final FutureJVppCore futureJVppCore) {
- super(futureJVppCore);
- }
-
- 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);
- }
-
- // static removed, cant use default from static content
- private byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) {
- final String[] split = ipv4Prefix.getValue().split("/");
- final byte[] addressBytes = ipv4AddressNoZoneToArray(split[0]);
- final byte[] mask = toByteMask(Byte.valueOf(split[1]));
- for (int i = 0; i < addressBytes.length; ++i) {
- addressBytes[i] &= mask[i];
- }
- return addressBytes;
- }
+ private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class);
@Override
- public ClassifyAddDelTable createClassifyTable(@Nonnull final AceIp aceIp,
- @Nullable final InterfaceMode mode,
- final int nextTableIndex,
- final int vlanTags) {
+ 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 ClassifyAddDelTable request = createClassifyTable(nextTableIndex);
+ final ClassifyAddDelTable request = createTable(nextTableIndex);
request.skipNVectors = 0; // match entire L2 and L3 header
request.matchNVectors = MATCH_N_VECTORS;
-
- boolean aceIsEmpty = true;
request.mask = new byte[TABLE_MASK_LENGTH];
final int baseOffset = getVlanTagsLen(vlanTags);
-
- 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 (aceIp.getDscp() != null) {
- aceIsEmpty = false;
- request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
- }
-
- if (aceIp.getProtocol() != null) { // Internet Protocol number
- request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
- }
-
- if (aceIp.getSourcePortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
- }
-
- if (aceIp.getDestinationPortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
- }
-
- if (ipVersion.getSourceIpv4Network() != null) {
- aceIsEmpty = false;
- System.arraycopy(toByteMask(ipVersion.getSourceIpv4Network()), 0, request.mask, baseOffset + SRC_IP_OFFSET,
- IP4_LEN);
- }
-
- if (ipVersion.getDestinationIpv4Network() != null) {
- aceIsEmpty = false;
- System
- .arraycopy(toByteMask(ipVersion.getDestinationIpv4Network()), 0, request.mask,
- baseOffset + DST_IP_OFFSET, IP4_LEN);
- }
-
+ boolean aceIsEmpty = ip4Mask(baseOffset, mode, aceIp, ipVersion, request, LOG);
if (aceIsEmpty) {
throw new IllegalArgumentException(
- String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
}
LOG.debug("ACE rule={} translated to table={}.", aceIp, request);
@@ -141,70 +62,25 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> implements Ipv4Transla
}
@Override
- public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
- @Nonnull final AceIp aceIp,
- @Nullable final InterfaceMode mode,
- final int tableIndex,
- final int vlanTags) {
+ public ClassifyAddDelSession 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 ClassifyAddDelSession request = createClassifySession(action, tableIndex);
-
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
request.match = new byte[TABLE_MASK_LENGTH];
- boolean noMatch = true;
final int baseOffset = getVlanTagsLen(vlanTags);
-
- 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 (aceIp.getProtocol() != null) {
- request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & aceIp.getProtocol());
- }
-
- if (aceIp.getDscp() != null) {
- noMatch = false;
- request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (aceIp.getDscp().getValue() << 2));
- }
-
- if (aceIp.getSourcePortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
- }
-
- if (aceIp.getDestinationPortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
- }
-
- if (ipVersion.getSourceIpv4Network() != null) {
- noMatch = false;
- System
- .arraycopy(toMatchValue(ipVersion.getSourceIpv4Network()), 0, request.match,
- baseOffset + SRC_IP_OFFSET,
- IP4_LEN);
- }
-
- if (ipVersion.getDestinationIpv4Network() != null) {
- noMatch = false;
- System.arraycopy(toMatchValue(ipVersion.getDestinationIpv4Network()), 0, request.match,
- baseOffset + DST_IP_OFFSET,
- IP4_LEN);
- }
-
+ boolean noMatch = ip4Match(baseOffset, mode, aceIp, ipVersion, request, LOG);
if (noMatch) {
throw new IllegalArgumentException(
- String.format("Ace %s does not define packet field match values", aceIp.toString()));
+ String.format("Ace %s does not define packet field match values", aceIp.toString()));
}
LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
return request;
}
-
- @Override
- protected void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex) {
- request.ip4TableIndex = tableIndex;
- }
}
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
index f1cccba92..b1186440d 100644
--- 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
@@ -19,142 +19,39 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.annotations.VisibleForTesting;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.BitSet;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
-import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
-import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
-import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
-import io.fd.vpp.jvpp.core.future.FutureJVppCore;
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 extends AbstractAceWriter<AceIp> {
+final class AceIp6Writer implements AceWriter<AceIp>, AclTranslator, Ip6AclTranslator {
@VisibleForTesting
static final int MATCH_N_VECTORS = 4; // number of 16B vectors
- private static final Logger LOG = LoggerFactory.getLogger(AceIp6Writer.class);
private static final int TABLE_MASK_LENGTH = 64;
- private static final int IP6_MASK_BIT_LENGTH = 128;
-
- private static final int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
- private static final int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET+2;
- private static final int DSCP_MASK1 = 0x0f;
- private static final int DSCP_MASK2 = 0xc0;
- private static final int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET+6;
- private static final int IP_PROTOCOL_MASK = 0xff;
- private static final int IP6_LEN = 16;
- private static final int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8;
- private static final int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN;
-
- public AceIp6Writer(@Nonnull final FutureJVppCore futureJVppCore) {
- super(futureJVppCore);
- }
-
- 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;
- }
+ private static final Logger LOG = LoggerFactory.getLogger(AceIp6Writer.class);
@Override
- public ClassifyAddDelTable createClassifyTable(@Nonnull final AceIp aceIp,
- @Nullable final InterfaceMode mode,
- final int nextTableIndex,
- final int vlanTags) {
+ 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 ClassifyAddDelTable request = createClassifyTable(nextTableIndex);
+ final ClassifyAddDelTable request = createTable(nextTableIndex);
request.skipNVectors = 0; // match entire L2 and L3 header
request.matchNVectors = MATCH_N_VECTORS;
-
- boolean aceIsEmpty = true;
request.mask = new byte[TABLE_MASK_LENGTH];
final int baseOffset = getVlanTagsLen(vlanTags);
-
- 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 (aceIp.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 (aceIp.getProtocol() != null) {
- aceIsEmpty = false;
- request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
- }
-
- if (aceIp.getSourcePortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
- }
-
- if (aceIp.getDestinationPortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
- }
-
- if (ipVersion.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 (ipVersion.getSourceIpv6Network() != null) {
- aceIsEmpty = false;
- final byte[] mask = toByteMask(ipVersion.getSourceIpv6Network());
- System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length);
- }
-
- if (ipVersion.getDestinationIpv6Network() != null) {
- aceIsEmpty = false;
- final byte[] mask = toByteMask(ipVersion.getDestinationIpv6Network());
- System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
- }
-
+ boolean aceIsEmpty = ip6Mask(baseOffset, mode, aceIp, ipVersion, request, LOG);
if (aceIsEmpty) {
throw new IllegalArgumentException(
String.format("Ace %s does not define packet field match values", aceIp.toString()));
@@ -165,68 +62,19 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
}
@Override
- public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
- @Nonnull final AceIp aceIp,
- @Nullable final InterfaceMode mode,
- final int tableIndex,
- final int vlanTags) {
+ public ClassifyAddDelSession 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 ClassifyAddDelSession request = createClassifySession(action, tableIndex);
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
request.match = new byte[TABLE_MASK_LENGTH];
- boolean noMatch = true;
final int baseOffset = getVlanTagsLen(vlanTags);
-
- 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 (aceIp.getDscp() != null) {
- noMatch = false;
- final int dscp = aceIp.getDscp().getValue();
- // set bits 4-9 of IP6 header:
- request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dscp >> 2));
- request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dscp << 6));
- }
-
- if (aceIp.getProtocol() != null) {
- noMatch = false;
- request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & aceIp.getProtocol());
- }
-
- if (aceIp.getSourcePortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
- }
-
- if (aceIp.getDestinationPortRange() != null) {
- LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
- }
-
- if (ipVersion.getFlowLabel() != null) {
- noMatch = false;
- final int flowLabel = ipVersion.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 (ipVersion.getSourceIpv6Network() != null) {
- noMatch = false;
- final byte[] match = toMatchValue(ipVersion.getSourceIpv6Network());
- System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN);
- }
-
- if (ipVersion.getDestinationIpv6Network() != null) {
- noMatch = false;
- final byte[] match = toMatchValue(ipVersion.getDestinationIpv6Network());
- System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
- }
-
+ boolean noMatch = ip6Match(baseOffset, mode, aceIp, ipVersion, request, LOG);
if (noMatch) {
throw new IllegalArgumentException(
String.format("Ace %s does not define packet field match values", aceIp.toString()));
@@ -235,9 +83,4 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
return request;
}
-
- @Override
- protected void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex) {
- request.ip6TableIndex = tableIndex;
- }
}
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
new file mode 100644
index 000000000..40a050a6d
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AceIpAndEthWriter.java
@@ -0,0 +1,120 @@
+/*
+ * 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.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<AceIpAndEth>, AclTranslator, L2AclTranslator, Ip4AclTranslator, Ip6AclTranslator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AceIpAndEthWriter.class);
+
+ private static int maskLength(@Nonnull final AceIpAndEth ace) {
+ if (ace.getAceIpVersion() != null) {
+ if (ace.getAceIpVersion() instanceof AceIpv4) {
+ return 48;
+ } else {
+ return 64;
+ }
+ }
+ return 16;
+ }
+
+ @Override
+ public ClassifyAddDelTable createTable(@Nonnull final AceIpAndEth ace, @Nullable final InterfaceMode mode,
+ final int nextTableIndex, final int vlanTags) {
+ final ClassifyAddDelTable request = createTable(nextTableIndex);
+ final int maskLength = maskLength(ace);
+ 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, LOG);
+ } else if (aceIpVersion instanceof AceIpv6) {
+ final AceIpv6 ipVersion = (AceIpv6) aceIpVersion;
+ aceIsEmpty &= ip6Mask(baseOffset, mode, ace, ipVersion, request, LOG);
+ } 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 ClassifyAddDelSession createSession(@Nonnull final PacketHandling action,
+ @Nonnull final AceIpAndEth ace,
+ @Nullable final InterfaceMode mode, final int tableIndex,
+ final int vlanTags) {
+ final ClassifyAddDelSession request = createSession(action, tableIndex);
+ request.match = new byte[maskLength(ace)];
+
+ 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, request, LOG);
+ } else if (aceIpVersion instanceof AceIpv6) {
+ final AceIpv6 ipVersion = (AceIpv6) aceIpVersion;
+ noMatch &= ip6Match(baseOffset, mode, ace, ipVersion, request, LOG);
+ } 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);
+ return request;
+ }
+}
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
index 7ba44f166..790b6d664 100644
--- 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
@@ -16,34 +16,38 @@
package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress;
-import io.fd.honeycomb.translate.write.WriteFailedException;
-import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
-import java.util.List;
-import javax.annotation.Nonnegative;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
+import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
import javax.annotation.Nonnull;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
+import 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;
-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;
/**
* Writer responsible for translation of ietf-acl model ACEs to VPP's classify tables and sessions.
+ *
+ * @param <T> type of access control list entry
*/
-interface AceWriter {
+interface AceWriter<T extends AceType> {
+ /**
+ * @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);
/**
- * Translates list of ACEs to chain of classify tables. Each ACE is translated into one classify table with single
- * classify session. Also initializes input_acl_set_interface request message DTO with first classify table of the
- * chain that was created.
- *
- * @param id uniquely identifies ietf-acl container
- * @param aces list of access control entries
- * @param mode interface mode (L2/L3)
- * @param defaultAction to be taken when packet that does not match any of rules defined in
- * @param request input_acl_set_interface request DTO
+ * @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
*/
- void write(@Nonnull final InstanceIdentifier<?> id, @Nonnull final List<Ace> aces,
- final InterfaceMode mode, final AccessLists.DefaultAction defaultAction,
- @Nonnull final InputAclSetInterface request, @Nonnegative final int vlanTags)
- throws WriteFailedException;
+ @Nonnull
+ ClassifyAddDelSession 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
new file mode 100644
index 000000000..9a931a923
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/AclTranslator.java
@@ -0,0 +1,64 @@
+/*
+ * 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 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 {
+
+ // 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 for now
+ int TABLE_MEM_SIZE = 8 * 1024;
+ int VLAN_TAG_LEN = 4;
+
+ default ClassifyAddDelTable createTable(final int nextTableIndex) {
+ final ClassifyAddDelTable request = new ClassifyAddDelTable();
+ request.isAdd = 1;
+ request.tableIndex = -1; // value not present
+ request.nbuckets = 1; // we expect exactly one session per table
+ request.nextTableIndex = nextTableIndex;
+ request.memorySize = TABLE_MEM_SIZE;
+ 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 9074684d7..4eac0fad6 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
@@ -41,10 +41,10 @@ import org.slf4j.LoggerFactory;
public class IetfAclCustomizer implements WriterCustomizer<Ingress> {
private static final Logger LOG = LoggerFactory.getLogger(IetfAclCustomizer.class);
- private final IetfAClWriter aclWriter;
+ private final IetfAclWriter aclWriter;
private final NamingContext interfaceContext;
- public IetfAclCustomizer(@Nonnull final IetfAClWriter aclWriter,
+ public IetfAclCustomizer(@Nonnull final IetfAclWriter 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
index 2fd00e39e..5814211f4 100644
--- 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
@@ -20,10 +20,11 @@ import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
-import io.fd.honeycomb.translate.v3po.interfaces.acl.IetfAclWriter;
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;
@@ -33,8 +34,10 @@ 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;
@@ -44,30 +47,35 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.cont
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.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.ietf.acl.base.attributes.access.lists.Acl;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.ace.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 {
+public final class IetfAclWriter implements JvppReplyConsumer, AclTranslator {
- private static final Logger LOG = LoggerFactory.getLogger(IetfAClWriter.class);
+ private static final Logger LOG = LoggerFactory.getLogger(IetfAclWriter.class);
+ private static final int NOT_DEFINED = -1;
private final FutureJVppCore jvpp;
- private Map<AclType, AceWriter> aceWriters = new HashMap<>();
+ private Map<AclType, AceWriter<? extends AceType>> aceWriters = new HashMap<>();
- public IetfAClWriter(@Nonnull final FutureJVppCore futureJVppCore) {
+ public IetfAclWriter(@Nonnull final FutureJVppCore futureJVppCore) {
this.jvpp = Preconditions.checkNotNull(futureJVppCore, "futureJVppCore should not be null");
- aceWriters.put(AclType.ETH, new AceEthWriter(futureJVppCore));
- aceWriters.put(AclType.IP4, new AceIp4Writer(futureJVppCore));
- aceWriters.put(AclType.IP6, new AceIp6Writer(futureJVppCore));
+ 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<Ace> aclToAceStream(@Nonnull final Acl assignedAcl,
@@ -77,12 +85,12 @@ public final class IetfAClWriter implements JvppReplyConsumer {
// ietf-acl updates are handled first, so we use writeContext.readAfter
final Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.Acl>
- aclOptional = writeContext.readAfter(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)));
+ 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();
+ acl = aclOptional.get();
final AccessListEntries accessListEntries = acl.getAccessListEntries();
checkArgument(accessListEntries != null, "access list entries not configured");
@@ -91,7 +99,7 @@ public final class IetfAClWriter implements JvppReplyConsumer {
}
void deleteAcl(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex)
- throws WriteFailedException {
+ throws WriteFailedException {
final ClassifyTableByInterface request = new ClassifyTableByInterface();
request.swIfIndex = swIfIndex;
@@ -110,7 +118,7 @@ public final class IetfAClWriter implements JvppReplyConsumer {
private void unassignClassifyTables(@Nonnull final InstanceIdentifier<?> id,
final ClassifyTableByInterfaceReply currentState)
- throws WriteFailedException {
+ throws WriteFailedException {
final InputAclSetInterface request = new InputAclSetInterface();
request.isAdd = 0;
request.swIfIndex = currentState.swIfIndex;
@@ -118,12 +126,12 @@ public final class IetfAClWriter implements JvppReplyConsumer {
request.ip4TableIndex = currentState.ip4TableId;
request.ip6TableIndex = currentState.ip6TableId;
final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
- jvpp.inputAclSetInterface(request);
+ jvpp.inputAclSetInterface(request);
getReplyForDelete(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
}
private void removeClassifyTable(@Nonnull final InstanceIdentifier<?> id, final int tableIndex)
- throws WriteFailedException {
+ throws WriteFailedException {
if (tableIndex == -1) {
return; // classify table id is absent
@@ -135,49 +143,138 @@ public final class IetfAClWriter implements JvppReplyConsumer {
}
void write(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex, @Nonnull final List<Acl> acls,
- final AccessLists.DefaultAction defaultAction, @Nullable final InterfaceMode mode, @Nonnull final WriteContext writeContext)
- throws WriteFailedException {
+ 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();
+ if (aceType instanceof AceIp && ((AceIp) aceType).getAceIpVersion() instanceof AceIpv4) {
+ return true;
+ }
+ if (aceType instanceof AceEth) {
+ return true; // L2 only rules are possible for IP4 traffic
+ }
+ if (aceType instanceof AceIpAndEth && ((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();
+ if (aceType instanceof AceIp && ((AceIp) aceType).getAceIpVersion() instanceof AceIpv6) {
+ return true;
+ }
+ if (aceType instanceof AceEth) {
+ return true; // L2 only rules are possible for IP6 traffic
+ }
+ if (aceType instanceof AceIpAndEth && ((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<Acl> acls, final AccessLists.DefaultAction defaultAction,
@Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags)
- throws WriteFailedException {
-
- // filter ACE entries and group by AceType
- final Map<AclType, List<Ace>> acesByType = acls.stream()
- .flatMap(acl -> aclToAceStream(acl, writeContext))
- .collect(Collectors.groupingBy(AclType::fromAce));
+ 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 = -1;
- request.ip4TableIndex = -1;
- request.ip6TableIndex = -1;
+ request.l2TableIndex = NOT_DEFINED;
+ request.ip4TableIndex = NOT_DEFINED;
+ request.ip6TableIndex = NOT_DEFINED;
+
+ if (InterfaceMode.L2.equals(mode)) {
+ final List<Ace> aces = getACEs(acls, writeContext, ace -> true);
+ request.l2TableIndex = writeAces(id, aces, defaultAction, mode, numberOfTags);
+ } else {
+ final List<Ace> ip4Aces = getACEs(acls, writeContext, (IetfAclWriter::appliesToIp4Path));
+ request.ip4TableIndex = writeAces(id, ip4Aces, defaultAction, mode, numberOfTags);
+ final List<Ace> ip6Aces = getACEs(acls, writeContext, (IetfAclWriter::appliesToIp6Path));
+ request.ip6TableIndex = writeAces(id, ip6Aces, defaultAction, mode, numberOfTags);
+ }
+
+ final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
+ jvpp.inputAclSetInterface(request);
+ getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ }
- // for each AceType:
- for (Map.Entry<AclType, List<Ace>> entry : acesByType.entrySet()) {
- final AclType aceType = entry.getKey();
- final List<Ace> aces = entry.getValue();
- LOG.trace("Processing ACEs of {} type: {}", aceType, aces);
+ private static List<Ace> getACEs(@Nonnull final List<Acl> acls, @Nonnull final WriteContext writeContext,
+ final Predicate<? super Ace> filter) {
+ return acls.stream().flatMap(acl -> aclToAceStream(acl, writeContext)).filter(filter)
+ .collect(Collectors.toList());
+ }
+
+ private int writeAces(final InstanceIdentifier<?> id, final List<Ace> aces,
+ final AccessLists.DefaultAction defaultAction, final InterfaceMode mode,
+ final int vlanTags) throws WriteFailedException {
+ if (aces.isEmpty()) {
+ return NOT_DEFINED;
+ }
- final AceWriter aceWriter = aceWriters.get(aceType);
+ int nextTableIndex = configureDefaultAction(id, defaultAction);
+ final ListIterator<Ace> 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.", aceType);
+ LOG.warn("AceProcessor for {} not registered. Skipping ACE.", ace.getClass());
} else {
- aceWriter.write(id, aces, mode, defaultAction, request, numberOfTags);
+ 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 ClassifyAddDelSession csRequest =
+ aceWriter.createSession(action, aceType, mode, nextTableIndex, vlanTags);
+ createClassifySession(id, csRequest);
}
}
+ return nextTableIndex;
+ }
- final CompletionStage<InputAclSetInterfaceReply> inputAclSetInterfaceReplyCompletionStage =
- jvpp.inputAclSetInterface(request);
- getReplyForWrite(inputAclSetInterfaceReplyCompletionStage.toCompletableFuture(), id);
+ 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<ClassifyAddDelTableReply> 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<ClassifyAddDelSessionReply> cs = jvpp.classifyAddDelSession(request);
+
+ getReplyForWrite(cs.toCompletableFuture(), id);
}
private enum AclType {
- ETH, IP4, IP6;
+ ETH, IP4, IP6, ETH_AND_IP;
@Nonnull
private static AclType fromAce(final Ace ace) {
@@ -194,6 +291,8 @@ public final class IetfAClWriter implements JvppReplyConsumer {
} else {
result = IP6;
}
+ } else if (aceType instanceof AceIpAndEth) {
+ result = ETH_AND_IP;
}
} catch (NullPointerException e) {
throw new IllegalArgumentException("Incomplete ACE: " + ace, e);
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
new file mode 100644
index 000000000..819561e78
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip4AclTranslator.java
@@ -0,0 +1,135 @@
+/*
+ * 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;
+import org.slf4j.Logger;
+
+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;
+
+ default boolean ip4Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv4HeaderFields ip4, final ClassifyAddDelTable request, final Logger log) {
+ 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) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
+ }
+ if (header.getDestinationPortRange() != null) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
+ }
+ 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 ClassifyAddDelSession request, final Logger log) {
+ 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 (header.getSourcePortRange() != null) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
+ }
+ if (header.getDestinationPortRange() != null) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
+ }
+ 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
new file mode 100644
index 000000000..eb2ec8c10
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/Ip6AclTranslator.java
@@ -0,0 +1,169 @@
+/*
+ * 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;
+import org.slf4j.Logger;
+
+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;
+
+ default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
+ final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request, final Logger log) {
+ 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) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
+ }
+ if (header.getDestinationPortRange() != null) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
+ }
+ 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 ClassifyAddDelSession request, final Logger log) {
+ 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) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
+ }
+ if (header.getDestinationPortRange() != null) {
+ log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
+ }
+ 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
new file mode 100644
index 000000000..a802ed3fa
--- /dev/null
+++ b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/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.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<String> 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<String> 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<String> 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<String> 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/SubInterfaceIetfAclCustomizer.java b/v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/ingress/SubInterfaceIetfAclCustomizer.java
index fe4e22142..fdefc0855 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<Ingress> {
private static final Logger LOG = LoggerFactory.getLogger(SubInterfaceIetfAclCustomizer.class);
- private final IetfAClWriter aclWriter;
+ private final IetfAclWriter aclWriter;
private final NamingContext interfaceContext;
- public SubInterfaceIetfAclCustomizer(@Nonnull final IetfAClWriter aclWriter,
+ public SubInterfaceIetfAclCustomizer(@Nonnull final IetfAclWriter aclWriter,
@Nonnull final NamingContext interfaceContext) {
this.aclWriter = checkNotNull(aclWriter, "aclWriter should not be null");
this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");