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.ingress;
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.vpp.util.Ipv4Translator;
24 import javax.annotation.Nonnull;
25 import javax.annotation.Nullable;
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.actions.PacketHandling;
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.AceIp;
28 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;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
30 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
31 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
32 import io.fd.vpp.jvpp.core.dto.InputAclSetInterface;
33 import io.fd.vpp.jvpp.core.future.FutureJVppCore;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.InterfaceMode;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 final class AceIp4Writer extends AbstractAceWriter<AceIp> implements Ipv4Translator {
41 static final int MATCH_N_VECTORS = 3; // number of 16B vectors
42 private static final Logger LOG = LoggerFactory.getLogger(AceIp4Writer.class);
43 private static final int TABLE_MASK_LENGTH = 48;
44 private static final int IP4_MASK_BIT_LENGTH = 32;
46 private static final int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
47 private static final int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET+2;
48 private static final int IP_VERSION_MASK = 0xf0;
49 private static final int DSCP_OFFSET = 15;
50 private static final int DSCP_MASK = 0xfc;
51 private static final int IP4_LEN = 4;
52 private static final int SRC_IP_OFFSET = IP_VERSION_OFFSET + 12;
53 private static final int DST_IP_OFFSET = SRC_IP_OFFSET + IP4_LEN;
55 public AceIp4Writer(@Nonnull final FutureJVppCore futureJVppCore) {
56 super(futureJVppCore);
59 private static byte[] toByteMask(final int prefixLength) {
60 final long mask = ((1L << prefixLength) - 1) << (IP4_MASK_BIT_LENGTH - prefixLength);
61 return Ints.toByteArray((int) mask);
64 private static byte[] toByteMask(final Ipv4Prefix ipv4Prefix) {
65 final int prefixLength = Byte.valueOf(ipv4Prefix.getValue().split("/")[1]);
66 return toByteMask(prefixLength);
69 // static removed, cant use default from static content
70 private byte[] toMatchValue(final Ipv4Prefix ipv4Prefix) {
71 final String[] split = ipv4Prefix.getValue().split("/");
72 final byte[] addressBytes = ipv4AddressNoZoneToArray(split[0]);
73 final byte[] mask = toByteMask(Byte.valueOf(split[1]));
74 for (int i = 0; i < addressBytes.length; ++i) {
75 addressBytes[i] &= mask[i];
81 public ClassifyAddDelTable createClassifyTable(@Nonnull final PacketHandling action,
82 @Nonnull final AceIp aceIp,
83 @Nullable final InterfaceMode mode,
84 final int nextTableIndex,
86 checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
87 final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
89 final ClassifyAddDelTable request = createClassifyTable(action, nextTableIndex);
90 request.skipNVectors = 0; // match entire L2 and L3 header
91 request.matchNVectors = MATCH_N_VECTORS;
93 boolean aceIsEmpty = true;
94 request.mask = new byte[TABLE_MASK_LENGTH];
96 final int baseOffset = getVlanTagsLen(vlanTags);
98 if (InterfaceMode.L2.equals(mode)) {
99 // in L2 mode we need to match ether type
100 request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
101 request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
104 // First 14 bytes represent l2 header (2x6 + etherType(2))
105 if (aceIp.getProtocol() != null) { // Internet Protocol number
106 request.mask[baseOffset + IP_VERSION_OFFSET] = (byte) IP_VERSION_MASK; // first 4 bits
109 if (aceIp.getDscp() != null) {
111 request.mask[baseOffset + DSCP_OFFSET] = (byte) DSCP_MASK; // first 6 bits
114 if (aceIp.getSourcePortRange() != null) {
115 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
118 if (aceIp.getDestinationPortRange() != null) {
119 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
122 if (ipVersion.getSourceIpv4Network() != null) {
124 System.arraycopy(toByteMask(ipVersion.getSourceIpv4Network()), 0, request.mask, baseOffset + SRC_IP_OFFSET,
128 if (ipVersion.getDestinationIpv4Network() != null) {
131 .arraycopy(toByteMask(ipVersion.getDestinationIpv4Network()), 0, request.mask,
132 baseOffset + DST_IP_OFFSET, IP4_LEN);
136 throw new IllegalArgumentException(
137 String.format("Ace %s does not define packet field match values", aceIp.toString()));
140 LOG.debug("ACE action={}, rule={} translated to table={}.", action, aceIp, request);
145 public ClassifyAddDelSession createClassifySession(@Nonnull final PacketHandling action,
146 @Nonnull final AceIp aceIp,
147 @Nullable final InterfaceMode mode,
148 final int tableIndex,
149 final int vlanTags) {
150 checkArgument(aceIp.getAceIpVersion() instanceof AceIpv4, "Expected AceIpv4 version, but was %", aceIp);
151 final AceIpv4 ipVersion = (AceIpv4) aceIp.getAceIpVersion();
153 final ClassifyAddDelSession request = createClassifySession(action, tableIndex);
155 request.match = new byte[TABLE_MASK_LENGTH];
156 boolean noMatch = true;
158 final int baseOffset = getVlanTagsLen(vlanTags);
160 if (InterfaceMode.L2.equals(mode)) {
161 // match IP4 etherType (0x0800)
162 request.match[baseOffset + ETHER_TYPE_OFFSET] = 0x08;
163 request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = 0x00;
166 if (aceIp.getProtocol() != null) {
167 request.match[baseOffset + IP_VERSION_OFFSET] =
168 (byte) (IP_VERSION_MASK & (aceIp.getProtocol().intValue() << 4));
171 if (aceIp.getDscp() != null) {
173 request.match[baseOffset + DSCP_OFFSET] = (byte) (DSCP_MASK & (aceIp.getDscp().getValue() << 2));
176 if (aceIp.getSourcePortRange() != null) {
177 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getSourcePortRange());
180 if (aceIp.getDestinationPortRange() != null) {
181 LOG.warn("L4 Header fields are not supported. Ignoring {}", aceIp.getDestinationPortRange());
184 if (ipVersion.getSourceIpv4Network() != null) {
187 .arraycopy(toMatchValue(ipVersion.getSourceIpv4Network()), 0, request.match,
188 baseOffset + SRC_IP_OFFSET,
192 if (ipVersion.getDestinationIpv4Network() != null) {
194 System.arraycopy(toMatchValue(ipVersion.getDestinationIpv4Network()), 0, request.match,
195 baseOffset + DST_IP_OFFSET,
200 throw new IllegalArgumentException(
201 String.format("Ace %s does not define packet field match values", aceIp.toString()));
204 LOG.debug("ACE action={}, rule={} translated to session={}.", action, aceIp, request);
209 protected void setClassifyTable(@Nonnull final InputAclSetInterface request, final int tableIndex) {
210 request.ip4TableIndex = tableIndex;