2 * Copyright (c) 2016 Cisco and/or its affiliates.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package io.fd.honeycomb.translate.v3po.interfaces.acl;
19 import static com.google.common.base.Preconditions.checkArgument;
21 import com.google.common.annotations.VisibleForTesting;
22 import com.google.common.primitives.Ints;
23 import io.fd.honeycomb.translate.v3po.util.Ipv4Translator;
24 import javax.annotation.Nonnull;
25 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;
26 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;
27 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;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
29 import org.openvpp.jvpp.core.dto.ClassifyAddDelSession;
30 import org.openvpp.jvpp.core.dto.ClassifyAddDelTable;
31 import org.openvpp.jvpp.core.dto.InputAclSetInterface;
32 import org.openvpp.jvpp.core.future.FutureJVppCore;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 final class AceIp4Writer extends AbstractAceWriter<AceIp> implements Ipv4Translator {
39 static final int MATCH_N_VECTORS = 3; // number of 16B vectors
40 private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class);
41 private static final int TABLE_MASK_LENGTH = 48;
42 private static final int IP4_MASK_BIT_LENGTH = 32;
44 private static final int IP_VERSION_OFFSET = 14; // first 14 bytes represent L2 header (2x6 + etherType(2))
45 private static final int IP_VERSION_MASK = 0xf0;
46 private static final int DSCP_OFFSET = 15;
47 private static final int DSCP_MASK = 0xfc;
48 private static final int IP4_LEN = 4;
49 private static final int SRC_IP_OFFSET = IP_VERSION_OFFSET + 12;
50 private static final int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN;
52 public AceIp4Writer(@Nonnull final FutureJVppCore futureJVppCore) {
53 super(futureJVppCore);
56 private static byte[] toByteMask(final int prefixLength) {
57 final long mask = ((1L << prefixLength) - 1) << (IP4_MASK_BIT_LENGTH - prefixLength);
58 return Ints.toByteArray((int) mask);
61 private static byte[] toByteMask(final Ipv4Prefix ipv4Prefix) {
62 final int prefixLength = Byte.valueOf(ipv4Prefix.getValue().split("/")[1]);
63 return toByteMask(prefixLength);
66 // static removed, cant use default from static content
67 private byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) {
68 final String[] split = ipv4Prefix.getValue().split("/");
69 final byte[] addressBytes = ipv4AddressNoZoneToArray(split[0]);
70 final byte[] mask = toByteMask(Byte.valueOf(split[1]));
71 for (int i = 0; i < addressBytes.length; ++i) {
72 addressBytes[i] &= mask[i];
78 public ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
79 @Nonnull final AceIp aceIp,
80 final int nextTableIndex,
82 checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
83 final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
85 final ClassifyAddDelTable request = createClassifyTable(action, nextTableIndex);
86 request.skipNVectors = 0; // match entire L2 and L3 header
87 request.matchNVectors = MATCH_N_VECTORS;
89 boolean aceIsEmpty = true;
90 request.mask = new byte[TABLE_MASK_LENGTH];
92 final int baseOffset = getVlanTagsLen(vlanTags);
94 // First 14 bytes represent l2 header (2x6 + etherType(2))
95 if (aceIp.getProtocol() != null) { // Internet Protocol number
96 request.mask[baseOffset + IP_VERSION_OFFSET] = (byte) IP_VERSION_MASK; // first 4 bits
99 if (aceIp.getDscp() != null) {
101 request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
104 if (aceIp.getSourcePortRange() != null) {
105 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
108 if (aceIp.getDestinationPortRange() != null) {
109 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
112 if (ipVersion.getSourceIpv4Network() != null) {
114 System.arraycopy(toByteMask(ipVersion.getSourceIpv4Network()), 0, request.mask, baseOffset + SRC_IP_OFFSET,
118 if (ipVersion.getDestinationIpv4Network() != null) {
121 .arraycopy(toByteMask(ipVersion.getDestinationIpv4Network()), 0, request.mask,
122 baseOffset + DST_IP_OFFSET, IP4_LEN);
126 throw new IllegalArgumentException(
127 String.format("Ace %s does not define packet field match values", aceIp.toString()));
130 LOG.debug("ACE action={}, rule={} translated to table={}.", action, aceIp, request);
135 public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
136 @Nonnull final AceIp aceIp,
137 final int tableIndex,
138 final int vlanTags) {
139 checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
140 final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
142 final ClassifyAddDelSession request = createClassifySession(action, tableIndex);
144 request.match = new byte[TABLE_MASK_LENGTH];
145 boolean noMatch = true;
147 final int baseOffset = getVlanTagsLen(vlanTags);
149 if (aceIp.getProtocol() != null) {
150 request.match[baseOffset + IP_VERSION_OFFSET] =
151 (byte) (IP_VERSION_MASK & (aceIp.getProtocol().intValue() << 4));
154 if (aceIp.getDscp() != null) {
156 request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (aceIp.getDscp().getValue() << 2));
159 if (aceIp.getSourcePortRange() != null) {
160 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
163 if (aceIp.getDestinationPortRange() != null) {
164 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
167 if (ipVersion.getSourceIpv4Network() != null) {
170 .arraycopy(toMatchValue(ipVersion.getSourceIpv4Network()), 0, request.match,
171 baseOffset + SRC_IP_OFFSET,
175 if (ipVersion.getDestinationIpv4Network() != null) {
177 System.arraycopy(toMatchValue(ipVersion.getDestinationIpv4Network()), 0, request.match,
178 baseOffset + DST_IP_OFFSET,
183 throw new IllegalArgumentException(
184 String.format("Ace %s does not define packet field match values", aceIp.toString()));
187 LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
192 protected void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex) {
193 request.ip4TableIndex = tableIndex;