HONEYCOMB-153: fix acls for sub-interfaces 37/2637/3
authorMarek Gradzki <mgradzki@cisco.com>
Mon, 5 Sep 2016 11:31:39 +0000 (13:31 +0200)
committerMarek Gradzki <mgradzki@cisco.com>
Tue, 6 Sep 2016 06:03:28 +0000 (06:03 +0000)
Change-Id: Ia75c2ebd62fb371fd60f860fe12761926f443b98
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
16 files changed:
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceAclCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/SubInterfaceCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AbstractAceWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceEthWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIp4Writer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIp6Writer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/IetfAClWriter.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/Readme.adoc
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/interfaces/acl/SubInterfaceIetfAclCustomizer.java
v3po/v3po2vpp/src/main/java/io/fd/honeycomb/translate/v3po/util/SubInterfaceUtils.java [moved from vpp-common/vpp-translate-utils/src/main/java/io/fd/honeycomb/translate/v3po/util/SubInterfaceUtils.java with 54% similarity]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceEthWriterTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIp4WriterTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIp6WriterTest.java
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIpWriterTestUtils.java [new file with mode: 0644]
v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/util/SubinterfaceUtilsTest.java [moved from vpp-common/vpp-translate-utils/src/test/java/io/fd/honeycomb/translate/v3po/util/SubinterfaceUtilsTest.java with 100% similarity]

index d4a3998..962801a 100644 (file)
@@ -18,13 +18,13 @@ package io.fd.honeycomb.translate.v3po.interfaces;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
+import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
+import io.fd.honeycomb.translate.v3po.util.NamingContext;
+import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
 import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
-import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
-import io.fd.honeycomb.translate.v3po.util.NamingContext;
-import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
@@ -47,7 +47,8 @@ public class SubInterfaceAclCustomizer extends FutureJVppCustomizer
     private final NamingContext interfaceContext;
     private final NamingContext classifyTableContext;
 
-    public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore vppApi, @Nonnull final NamingContext interfaceContext,
+    public SubInterfaceAclCustomizer(@Nonnull final FutureJVppCore vppApi,
+                                     @Nonnull final NamingContext interfaceContext,
                                      @Nonnull final NamingContext classifyTableContext) {
         super(vppApi);
         this.interfaceContext = checkNotNull(interfaceContext, "interfaceContext should not be null");
index 38164bf..bfaa42e 100644 (file)
 package io.fd.honeycomb.translate.v3po.interfaces;
 
 import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getNumberOfTags;
 import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getSubInterfaceName;
 import static io.fd.honeycomb.translate.v3po.util.TranslateUtils.booleanToByte;
 
 import com.google.common.base.Preconditions;
 import io.fd.honeycomb.translate.spi.write.ListWriterCustomizer;
 import io.fd.honeycomb.translate.v3po.util.FutureJVppCustomizer;
-import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
-import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
+import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
+import io.fd.honeycomb.translate.write.WriteContext;
 import io.fd.honeycomb.translate.write.WriteFailedException;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CompletionStage;
 import javax.annotation.Nonnull;
@@ -44,7 +44,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.MatchType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.Default;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.match.attributes.match.type.vlan.tagged.VlanTagged;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.openvpp.jvpp.VppBaseCallException;
@@ -108,7 +107,7 @@ public class SubInterfaceCustomizer extends FutureJVppCustomizer
         request.subId = Math.toIntExact(subInterface.getIdentifier().intValue());
         request.swIfIndex = swIfIndex;
 
-        final int numberOfTags = getNumberOfTags(subInterface);
+        final int numberOfTags = getNumberOfTags(subInterface.getTags());
         switch (numberOfTags) {
             case 0:
                 request.noTags = 1;
@@ -155,18 +154,6 @@ public class SubInterfaceCustomizer extends FutureJVppCustomizer
         request.innerVlanIdAny = booleanToByte(Dot1qTag.VlanId.Enumeration.Any.equals(vlanId.getEnumeration()));
     }
 
-    private static int getNumberOfTags(@Nonnull final SubInterface subInterface) {
-        final Tags tags = subInterface.getTags();
-        if (tags == null) {
-            return 0;
-        }
-        final List<Tag> tagList = tags.getTag();
-        if (tagList == null) {
-            return 0;
-        }
-        return tagList.size();
-    }
-
     private static short dot1qVlanIdToShort(@Nullable Dot1qVlanId dot1qVlanId) {
         if (dot1qVlanId == null) {
             return 0; // tell VPP that optional argument is missing
index 21a7107..eeabff4 100644 (file)
 
 package io.fd.honeycomb.translate.v3po.interfaces.acl;
 
+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.util.RWUtils;
 import io.fd.honeycomb.translate.v3po.util.TranslateUtils;
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
 import java.util.List;
 import java.util.concurrent.CompletionStage;
 import java.util.stream.Collector;
+import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
 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;
@@ -53,6 +56,9 @@ abstract class AbstractAceWriter<T extends AceType> implements AceWriter {
     // 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 Collector<PacketHandling, ?, PacketHandling> SINGLE_ITEM_COLLECTOR =
         RWUtils.singleItemCollector();
 
@@ -68,11 +74,13 @@ abstract class AbstractAceWriter<T extends AceType> implements AceWriter {
      * @param action         packet handling action (permit/deny)
      * @param ace            ACE to be translated
      * @param nextTableIndex classify table index
+     * @param vlanTags       number of vlan tags
      * @return classify table that represents given ACE
      */
     protected abstract ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
                                                                @Nonnull final T ace,
-                                                               final int nextTableIndex);
+                                                               final int nextTableIndex,
+                                                               final int vlanTags);
 
     /**
      * Creates classify session for given ACE.
@@ -80,11 +88,13 @@ abstract class AbstractAceWriter<T extends AceType> implements AceWriter {
      * @param action     packet handling action (permit/deny)
      * @param ace        ACE to be translated
      * @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,
-                                                                   final int tableIndex);
+                                                                   final int tableIndex,
+                                                                   final int vlanTags);
 
     /**
      * Sets classify table index for input_acl_set_interface request.
@@ -94,21 +104,24 @@ abstract class AbstractAceWriter<T extends AceType> implements AceWriter {
      */
     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,
-                            @Nonnull final InputAclSetInterface request)
+                            @Nonnull final InputAclSetInterface request, @Nonnegative final int vlanTags)
         throws VppBaseCallException, WriteTimeoutException {
         final PacketHandling action = aces.stream().map(ace -> ace.getActions().getPacketHandling()).distinct()
             .collect(SINGLE_ITEM_COLLECTOR);
 
+        checkArgument(vlanTags >= 0 && vlanTags <= 2, "Number of vlan tags %s is not in [0,2] range");
+
         int nextTableIndex = -1;
         for (final Ace ace : aces) {
             // Create table + session per entry
 
             final ClassifyAddDelTable ctRequest =
-                createClassifyTable(action, (T) ace.getMatches().getAceType(), nextTableIndex);
+                createClassifyTable(action, (T) ace.getMatches().getAceType(), nextTableIndex, vlanTags);
             nextTableIndex = createClassifyTable(id, ctRequest);
             createClassifySession(id,
-                createClassifySession(action, (T) ace.getMatches().getAceType(), nextTableIndex));
+                createClassifySession(action, (T) ace.getMatches().getAceType(), nextTableIndex, vlanTags));
         }
         setClassifyTable(request, nextTableIndex);
     }
@@ -160,4 +173,8 @@ abstract class AbstractAceWriter<T extends AceType> implements AceWriter {
 
         return request;
     }
+
+    protected int getVlanTagsLen(final int vlanTags) {
+        return vlanTags * VLAN_TAG_LEN;
+    }
 }
index 1240a29..d204e16 100644 (file)
@@ -43,7 +43,8 @@ final class AceEthWriter extends AbstractAceWriter<AceEth> {
     @Override
     public ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
                                                    @Nonnull final AceEth aceEth,
-                                                   @Nonnull final int nextTableIndex) {
+                                                   @Nonnull final int nextTableIndex,
+                                                   final int vlanTags) {
         final ClassifyAddDelTable request = createClassifyTable(action, nextTableIndex);
 
         request.mask = new byte[16];
@@ -101,7 +102,8 @@ final class AceEthWriter extends AbstractAceWriter<AceEth> {
     @Override
     public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
                                                        @Nonnull final AceEth aceEth,
-                                                       @Nonnull final int tableIndex) {
+                                                       @Nonnull final int tableIndex,
+                                                       final int vlanTags) {
         final ClassifyAddDelSession request = createClassifySession(action, tableIndex);
 
         request.match = new byte[16];
index b2a9613..857f003 100644 (file)
@@ -77,7 +77,8 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> {
     @Override
     public ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
                                                    @Nonnull final AceIp aceIp,
-                                                   final int nextTableIndex) {
+                                                   final int nextTableIndex,
+                                                   final int vlanTags) {
         checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
         final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
 
@@ -88,14 +89,16 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> {
         boolean aceIsEmpty = true;
         request.mask = new byte[TABLE_MASK_LENGTH];
 
+        final int baseOffset = getVlanTagsLen(vlanTags);
+
         // First 14 bytes represent l2 header (2x6 + etherType(2))
         if (aceIp.getProtocol() != null) { // Internet Protocol number
-            request.mask[IP_VERSION_OFFSET] = (byte) IP_VERSION_MASK; // first 4 bits
+            request.mask[baseOffset + IP_VERSION_OFFSET] = (byte) IP_VERSION_MASK; // first 4 bits
         }
 
         if (aceIp.getDscp() != null) {
             aceIsEmpty = false;
-            request.mask[DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
+            request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
         }
 
         if (aceIp.getSourcePortRange() != null) {
@@ -108,13 +111,15 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> {
 
         if (ipVersion.getSourceIpv4Network() != null) {
             aceIsEmpty = false;
-            System.arraycopy(toByteMask(ipVersion.getSourceIpv4Network()), 0, request.mask, SRC_IP_OFFSET, IP4_LEN);
+            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, DST_IP_OFFSET, IP4_LEN);
+                .arraycopy(toByteMask(ipVersion.getDestinationIpv4Network()), 0, request.mask,
+                    baseOffset + DST_IP_OFFSET, IP4_LEN);
         }
 
         if (aceIsEmpty) {
@@ -132,7 +137,8 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> {
     @Override
     public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
                                                        @Nonnull final AceIp aceIp,
-                                                       final int tableIndex) {
+                                                       final int tableIndex,
+                                                       final int vlanTags) {
         checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
         final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
 
@@ -141,13 +147,16 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> {
         request.match = new byte[TABLE_MASK_LENGTH];
         boolean noMatch = true;
 
+        final int baseOffset = getVlanTagsLen(vlanTags);
+
         if (aceIp.getProtocol() != null) {
-            request.match[IP_VERSION_OFFSET] = (byte) (IP_VERSION_MASK & (aceIp.getProtocol().intValue() << 4));
+            request.match[baseOffset + IP_VERSION_OFFSET] =
+                (byte) (IP_VERSION_MASK & (aceIp.getProtocol().intValue() << 4));
         }
 
         if (aceIp.getDscp() != null) {
             noMatch = false;
-            request.match[DSCP_OFFSET] = (byte) (DSCP_MASK & (aceIp.getDscp().getValue() << 2));
+            request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (aceIp.getDscp().getValue() << 2));
         }
 
         if (aceIp.getSourcePortRange() != null) {
@@ -160,12 +169,15 @@ final class AceIp4Writer extends AbstractAceWriter<AceIp> {
 
         if (ipVersion.getSourceIpv4Network() != null) {
             noMatch = false;
-            System.arraycopy(toMatchValue(ipVersion.getSourceIpv4Network()), 0, request.match, SRC_IP_OFFSET, IP4_LEN);
+            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, DST_IP_OFFSET,
+            System.arraycopy(toMatchValue(ipVersion.getDestinationIpv4Network()), 0, request.match,
+                baseOffset + DST_IP_OFFSET,
                 IP4_LEN);
         }
 
index c46f2e1..d847ed8 100644 (file)
@@ -92,7 +92,8 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
     @Override
     public ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
                                                    @Nonnull final AceIp aceIp,
-                                                   final int nextTableIndex) {
+                                                   final int nextTableIndex,
+                                                   final int vlanTags) {
         checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp);
         final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion();
 
@@ -102,15 +103,18 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
 
         boolean aceIsEmpty = true;
         request.mask = new byte[TABLE_MASK_LENGTH];
+
+        final int baseOffset = getVlanTagsLen(vlanTags);
+
         if (aceIp.getProtocol() != null) {
-            request.mask[IP_VERSION_OFFSET] |= IP_VERSION_MASK;
+            request.mask[baseOffset + IP_VERSION_OFFSET] |= IP_VERSION_MASK;
         }
 
         if (aceIp.getDscp() != null) {
             aceIsEmpty = false;
             // DCSP (bits 4-9 of IP6 header)
-            request.mask[IP_VERSION_OFFSET] |= DSCP_MASK1;
-            request.mask[IP_VERSION_OFFSET + 1] |= DSCP_MASK2;
+            request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1;
+            request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2;
         }
 
         if (aceIp.getSourcePortRange() != null) {
@@ -124,21 +128,21 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
         if (ipVersion.getFlowLabel() != null) {
             aceIsEmpty = false;
             // bits 12-31
-            request.mask[IP_VERSION_OFFSET + 1] |= (byte) 0x0f;
-            request.mask[IP_VERSION_OFFSET + 2] = (byte) 0xff;
-            request.mask[IP_VERSION_OFFSET + 3] = (byte) 0xff;
+            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, SRC_IP_OFFSET, mask.length);
+            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, DST_IP_OFFSET, mask.length);
+            System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
         }
 
         if (aceIsEmpty) {
@@ -157,7 +161,8 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
     @Override
     public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
                                                        @Nonnull final AceIp aceIp,
-                                                       final int tableIndex) {
+                                                       final int tableIndex,
+                                                       final int vlanTags) {
         checkArgument(aceIp.getAceIpVersion() instanceof AceIpv6, "Expected AceIpv6 version, but was %", aceIp);
         final AceIpv6 ipVersion = (AceIpv6) aceIp.getAceIpVersion();
 
@@ -165,16 +170,19 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
         request.match = new byte[TABLE_MASK_LENGTH];
         boolean noMatch = true;
 
+        final int baseOffset = getVlanTagsLen(vlanTags);
+
         if (aceIp.getProtocol() != null) {
-            request.match[IP_VERSION_OFFSET] |= (byte) (IP_VERSION_MASK & (aceIp.getProtocol().intValue() << 4));
+            request.match[baseOffset + IP_VERSION_OFFSET] |=
+                (byte) (IP_VERSION_MASK & (aceIp.getProtocol().intValue() << 4));
         }
 
         if (aceIp.getDscp() != null) {
             noMatch = false;
             final int dscp = aceIp.getDscp().getValue();
             // set bits 4-9 of IP6 header:
-            request.match[IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dscp >> 2));
-            request.match[IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dscp << 6));
+            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.getSourcePortRange() != null) {
@@ -189,21 +197,21 @@ final class AceIp6Writer extends AbstractAceWriter<AceIp> {
             noMatch = false;
             final int flowLabel = ipVersion.getFlowLabel().getValue().intValue();
             // bits 12-31
-            request.match[IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16));
-            request.match[IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8));
-            request.match[IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel);
+            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, SRC_IP_OFFSET, IP6_LEN);
+            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, DST_IP_OFFSET, IP6_LEN);
+            System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
         }
 
         if (noMatch) {
index 2d66619..9343186 100644 (file)
@@ -18,6 +18,7 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl;
 
 import io.fd.honeycomb.translate.v3po.util.WriteTimeoutException;
 import java.util.List;
+import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.acl.access.list.entries.Ace;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -39,5 +40,6 @@ interface AceWriter {
      * @param request input_acl_set_interface request DTO
      */
     void write(@Nonnull final InstanceIdentifier<?> id, @Nonnull final List<Ace> aces,
-               @Nonnull final InputAclSetInterface request) throws VppBaseCallException, WriteTimeoutException;
+               @Nonnull final InputAclSetInterface request, @Nonnegative final int vlanTags)
+        throws VppBaseCallException, WriteTimeoutException;
 }
index f4ba56d..a25ddac 100644 (file)
@@ -30,6 +30,7 @@ import java.util.Map;
 import java.util.concurrent.CompletionStage;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.annotation.Nonnegative;
 import javax.annotation.Nonnull;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.AclBase;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160708.access.lists.AclKey;
@@ -121,6 +122,12 @@ public final class IetfAClWriter {
     void write(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex, @Nonnull final List<Acl> acls,
                @Nonnull final WriteContext writeContext)
         throws VppBaseCallException, WriteTimeoutException {
+        write(id, swIfIndex, acls, writeContext, 0);
+    }
+
+    void write(@Nonnull final InstanceIdentifier<?> id, final int swIfIndex, @Nonnull final List<Acl> acls,
+               @Nonnull final WriteContext writeContext, @Nonnegative final int numberOfTags)
+        throws VppBaseCallException, WriteTimeoutException {
 
         // filter ACE entries and group by AceType
         final Map<AclType, List<Ace>> acesByType = acls.stream()
@@ -147,7 +154,7 @@ public final class IetfAClWriter {
             if (aceWriter == null) {
                 LOG.warn("AceProcessor for {} not registered. Skipping ACE.", aceType);
             } else {
-                aceWriter.write(id, aces, request);
+                aceWriter.write(id, aces, request, numberOfTags);
             }
         }
 
index e59f72a..15b1b8c 100644 (file)
@@ -26,7 +26,4 @@ To check how ietf-acl model was translated to classify tables/session, low-level
 VPP classfier works in form of offsets and masks of 16B units.
 The offset always starts at the beginning of L2 Ethernet header
 of input packet. Because IP header can have variable length,
-source/destination port matching (L4 features of ietf-acl model) is not possible.
-
-Current implementation also assumes constant Ethernet header size
-(802.1Q headers are not supported).
\ No newline at end of file
+source/destination port matching (L4 features of ietf-acl model) is not possible.
\ No newline at end of file
index 8942691..989aeb5 100644 (file)
@@ -18,7 +18,10 @@ package io.fd.honeycomb.translate.v3po.interfaces.acl;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils.getNumberOfTags;
 
+import com.google.common.base.Optional;
 import io.fd.honeycomb.translate.spi.write.WriterCustomizer;
 import io.fd.honeycomb.translate.v3po.util.NamingContext;
 import io.fd.honeycomb.translate.v3po.util.SubInterfaceUtils;
@@ -73,8 +76,14 @@ public class SubInterfaceIetfAclCustomizer implements WriterCustomizer<IetfAcl>
         checkArgument(accessLists != null && accessLists.getAcl() != null,
             "ietf-acl container does not define acl list");
 
+        final Optional<SubInterface> subInterfaceOptional =
+            writeContext.readAfter(id.firstIdentifierOf(SubInterface.class));
+        checkState(subInterfaceOptional.isPresent(), "Could not read SubInterface data object for %s", id);
+        final SubInterface subInterface = subInterfaceOptional.get();
+
         try {
-            aclWriter.write(id, subInterfaceIndex, accessLists.getAcl(), writeContext);
+            aclWriter.write(id, subInterfaceIndex, accessLists.getAcl(), writeContext,
+                getNumberOfTags(subInterface.getTags()));
         } catch (VppBaseCallException e) {
             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
         }
 
 package io.fd.honeycomb.translate.v3po.util;
 
+import java.util.List;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nullable;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.Tags;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.vlan.rev150527.sub._interface.base.attributes.tags.Tag;
+
 public final class SubInterfaceUtils {
 
     private SubInterfaceUtils() {
@@ -25,4 +31,22 @@ public final class SubInterfaceUtils {
     public static String getSubInterfaceName(final String superIfName, final int subIfaceId) {
         return String.format("%s.%d", superIfName, subIfaceId);
     }
+
+    /**
+     * Returns number of sub-interface tags.
+     *
+     * @param tags data object that represents sub-interface tags
+     * @return number of sub interface tags
+     */
+    @Nonnegative
+    public static int getNumberOfTags(@Nullable final Tags tags) {
+        if (tags == null) {
+            return 0;
+        }
+        final List<Tag> tagList = tags.getTag();
+        if (tagList == null) {
+            return 0;
+        }
+        return tagList.size();
+    }
 }
index a32659a..b5b85de 100644 (file)
@@ -57,7 +57,7 @@ public class AceEthWriterTest {
     @Test
     public void testGetClassifyAddDelTableRequest() throws Exception {
         final int nextTableIndex = 42;
-        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceEth, nextTableIndex);
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceEth, nextTableIndex, 0);
 
         assertEquals(1, request.isAdd);
         assertEquals(-1, request.tableIndex);
@@ -81,7 +81,7 @@ public class AceEthWriterTest {
     @Test
     public void testGetClassifyAddDelSessionRequest() throws Exception {
         final int tableIndex = 123;
-        final ClassifyAddDelSession request = writer.createClassifySession(action, aceEth, tableIndex);
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceEth, tableIndex, 0);
 
         assertEquals(1, request.isAdd);
         assertEquals(tableIndex, request.tableIndex);
index 95b8fc5..bc34a53 100644 (file)
@@ -16,7 +16,8 @@
 
 package io.fd.honeycomb.translate.v3po.interfaces.acl;
 
-import static org.junit.Assert.assertArrayEquals;
+import static io.fd.honeycomb.translate.v3po.interfaces.acl.AbstractAceWriter.VLAN_TAG_LEN;
+import static io.fd.honeycomb.translate.v3po.interfaces.acl.AceIpWriterTestUtils.assertArrayEqualsWithOffset;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.MockitoAnnotations.initMocks;
 
@@ -58,11 +59,8 @@ public class AceIp4WriterTest {
             .build();
     }
 
-    @Test
-    public void testGetClassifyAddDelTableRequest() throws Exception {
-        final int nextTableIndex = 42;
-        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex);
-
+    private static void verifyTableRequest(final ClassifyAddDelTable request, final int nextTableIndex,
+                                           final int vlanTags) {
         assertEquals(1, request.isAdd);
         assertEquals(-1, request.tableIndex);
         assertEquals(1, request.nbuckets);
@@ -77,14 +75,12 @@ public class AceIp4WriterTest {
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1,
             -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
-        assertArrayEquals(expectedMask, request.mask);
-    }
+        assertArrayEqualsWithOffset(expectedMask, request.mask, vlanTags * VLAN_TAG_LEN);
 
-    @Test
-    public void testGetClassifyAddDelSessionRequest() throws Exception {
-        final int tableIndex = 123;
-        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex);
+    }
 
+    private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex,
+                                             final int vlanTags) {
         assertEquals(1, request.isAdd);
         assertEquals(tableIndex, request.tableIndex);
         assertEquals(0, request.hitNextIndex);
@@ -94,7 +90,55 @@ public class AceIp4WriterTest {
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 1, 2,
             4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
-        assertArrayEquals(expectedMatch, request.match);
+        assertArrayEqualsWithOffset(expectedMatch, request.match, vlanTags * VLAN_TAG_LEN);
+
+    }
+
+    @Test
+    public void testGetClassifyAddDelTableRequest() throws Exception {
+        final int nextTableIndex = 42;
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex, 0);
+        verifyTableRequest(request, nextTableIndex, 0);
+    }
+
+    @Test
+    public void testGetClassifyAddDelTableRequest1VlanTag() throws Exception {
+        final int nextTableIndex = 42;
+        final int vlanTags = 1;
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex, vlanTags);
+        verifyTableRequest(request, nextTableIndex, vlanTags);
+    }
+
+    @Test
+    public void testGetClassifyAddDelTableRequest2VlanTags() throws Exception {
+        final int nextTableIndex = 42;
+        final int vlanTags = 2;
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex, vlanTags);
+        verifyTableRequest(request, nextTableIndex, vlanTags);
+    }
+
+    @Test
+    public void testGetClassifyAddDelSessionRequest() throws Exception {
+        final int tableIndex = 123;
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex, 0);
+        verifySessionRequest(request, tableIndex, 0);
+    }
+
+    @Test
+    public void testGetClassifyAddDelSessionRequest1VlanTag() throws Exception {
+        final int tableIndex = 123;
+        final int vlanTags = 1;
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex, vlanTags);
+        verifySessionRequest(request, tableIndex, vlanTags);
+    }
+
+    @Test
+    public void testGetClassifyAddDelSessionRequest2VlanTags() throws Exception {
+        final int tableIndex = 123;
+        final int vlanTags = 2;
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex, vlanTags);
+
+        verifySessionRequest(request, tableIndex, vlanTags);
     }
 
     @Test
index 1818468..4af240c 100644 (file)
@@ -16,7 +16,8 @@
 
 package io.fd.honeycomb.translate.v3po.interfaces.acl;
 
-import static org.junit.Assert.assertArrayEquals;
+import static io.fd.honeycomb.translate.v3po.interfaces.acl.AbstractAceWriter.VLAN_TAG_LEN;
+import static io.fd.honeycomb.translate.v3po.interfaces.acl.AceIpWriterTestUtils.assertArrayEqualsWithOffset;
 import static org.junit.Assert.assertEquals;
 import static org.mockito.MockitoAnnotations.initMocks;
 
@@ -60,11 +61,9 @@ public class AceIp6WriterTest {
             .build();
     }
 
-    @Test
-    public void testGetClassifyAddDelTableRequest() throws Exception {
-        final int nextTableIndex = 42;
-        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex);
 
+    private static void verifyTableRequest(final ClassifyAddDelTable request, final int nextTableIndex,
+                                           final int vlanTags) {
         assertEquals(1, request.isAdd);
         assertEquals(-1, request.tableIndex);
         assertEquals(1, request.nbuckets);
@@ -89,14 +88,12 @@ public class AceIp6WriterTest {
             // padding to multiple of 16B:
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
-        assertArrayEquals(expectedMask, request.mask);
-    }
+        assertArrayEqualsWithOffset(expectedMask, request.mask, vlanTags * VLAN_TAG_LEN);
 
-    @Test
-    public void testGetClassifyAddDelSessionRequest() throws Exception {
-        final int tableIndex = 123;
-        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex);
+    }
 
+    private static void verifySessionRequest(final ClassifyAddDelSession request, final int tableIndex,
+                                             final int vlanTags) {
         assertEquals(1, request.isAdd);
         assertEquals(tableIndex, request.tableIndex);
         assertEquals(0, request.hitNextIndex);
@@ -116,7 +113,54 @@ public class AceIp6WriterTest {
             // padding to multiple of 16B:
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0
         };
-        assertArrayEquals(expectedMatch, request.match);
+        assertArrayEqualsWithOffset(expectedMatch, request.match, vlanTags * VLAN_TAG_LEN);
+
+    }
+
+    @Test
+    public void testGetClassifyAddDelTableRequest() throws Exception {
+        final int nextTableIndex = 42;
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex, 0);
+        verifyTableRequest(request, nextTableIndex, 0);
+    }
+
+    @Test
+    public void testGetClassifyAddDelTableRequest1VlanTag() throws Exception {
+        final int nextTableIndex = 42;
+        final int vlanTags = 1;
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex, vlanTags);
+        verifyTableRequest(request, nextTableIndex, vlanTags);
+    }
+
+    @Test
+    public void testGetClassifyAddDelTableRequest2VlanTag() throws Exception {
+        final int nextTableIndex = 42;
+        final int vlanTags = 2;
+        final ClassifyAddDelTable request = writer.createClassifyTable(action, aceIp, nextTableIndex, vlanTags);
+        verifyTableRequest(request, nextTableIndex, vlanTags);
+    }
+
+    @Test
+    public void testGetClassifyAddDelSessionRequest() throws Exception {
+        final int tableIndex = 123;
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex, 0);
+        verifySessionRequest(request, tableIndex, 0);
+    }
+
+    @Test
+    public void testGetClassifyAddDelSessionRequest1VlanTag() throws Exception {
+        final int tableIndex = 123;
+        final int vlanTags = 1;
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex, vlanTags);
+        verifySessionRequest(request, tableIndex, vlanTags);
+    }
+
+    @Test
+    public void testGetClassifyAddDelSessionRequest2VlanTag() throws Exception {
+        final int tableIndex = 123;
+        final int vlanTags = 2;
+        final ClassifyAddDelSession request = writer.createClassifySession(action, aceIp, tableIndex, vlanTags);
+        verifySessionRequest(request, tableIndex, vlanTags);
     }
 
     @Test
diff --git a/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIpWriterTestUtils.java b/v3po/v3po2vpp/src/test/java/io/fd/honeycomb/translate/v3po/interfaces/acl/AceIpWriterTestUtils.java
new file mode 100644 (file)
index 0000000..6b176b6
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.translate.v3po.interfaces.acl;
+
+import static org.junit.Assert.assertArrayEquals;
+
+final class AceIpWriterTestUtils {
+
+    private AceIpWriterTestUtils() {
+        throw new UnsupportedOperationException("This utility class cannot be instantiated");
+    }
+
+    protected static void assertArrayEqualsWithOffset(final byte[] baseExpected, final byte[] actual,
+                                                      final int offset) {
+        byte[] expected = new byte[baseExpected.length];
+        System.arraycopy(baseExpected, 0, expected, offset, expected.length - offset);
+
+        assertArrayEquals(expected, actual);
+    }
+}