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.common;
19 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelSession;
20 import io.fd.vpp.jvpp.core.dto.ClassifyAddDelTable;
21 import java.net.InetAddress;
22 import java.net.UnknownHostException;
23 import java.util.BitSet;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpHeaderFields;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160708.AclIpv6HeaderFields;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.acl.rev161214.InterfaceMode;
29 interface Ip6AclTranslator {
31 int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
32 int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET + 2;
33 int DSCP_MASK1 = 0x0f;
34 int DSCP_MASK2 = 0xc0;
35 int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET + 6;
36 int IP_PROTOCOL_MASK = 0xff;
38 int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8;
39 int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN;
40 int SRC_PORT_OFFSET = DST_IP_OFFSET + IP6_LEN;
41 int DST_PORT_OFFSET = SRC_PORT_OFFSET + 2;
43 default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
44 final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request) {
45 boolean aceIsEmpty = true;
46 if (InterfaceMode.L2.equals(mode)) {
47 // in L2 mode we need to match ether type
48 request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
49 request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
51 if (header.getDscp() != null) {
53 // DCSP (bits 4-9 of IP6 header)
54 request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1;
55 request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2;
57 if (header.getProtocol() != null) { // Internet Protocol number
59 request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
61 if (ip6.getFlowLabel() != null) {
64 request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) 0x0f;
65 request.mask[baseOffset + IP_VERSION_OFFSET + 2] = (byte) 0xff;
66 request.mask[baseOffset + IP_VERSION_OFFSET + 3] = (byte) 0xff;
68 if (header.getSourcePortRange() != null) {
69 // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
71 request.mask[baseOffset + SRC_PORT_OFFSET] = (byte) 0xff;
72 request.mask[baseOffset + SRC_PORT_OFFSET + 1] = (byte) 0xff;
74 if (header.getDestinationPortRange() != null) {
75 // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
77 request.mask[baseOffset + DST_PORT_OFFSET] = (byte) 0xff;
78 request.mask[baseOffset + DST_PORT_OFFSET + 1] = (byte) 0xff;
80 if (ip6.getSourceIpv6Network() != null) {
82 final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network());
83 System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length);
85 if (ip6.getDestinationIpv6Network() != null) {
87 final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network());
88 System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
93 default boolean ip6Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
94 final AclIpv6HeaderFields ip6, final Integer srcPort, final Integer dstPort, final ClassifyAddDelSession request) {
95 boolean noMatch = true;
96 if (InterfaceMode.L2.equals(mode)) {
97 // match IP6 etherType (0x86dd)
98 request.match[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0x86;
99 request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xdd;
101 if (header.getDscp() != null) {
103 final int dcsp = header.getDscp().getValue();
104 // set bits 4-9 of IP6 header:
105 request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dcsp >> 2));
106 request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dcsp << 6));
108 if (header.getProtocol() != null) { // Internet Protocol number
110 request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
112 if (ip6.getFlowLabel() != null) {
114 final int flowLabel = ip6.getFlowLabel().getValue().intValue();
116 request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16));
117 request.match[baseOffset + IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8));
118 request.match[baseOffset + IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel);
120 if (header.getSourcePortRange() != null) {
121 // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
123 request.match[baseOffset + SRC_PORT_OFFSET] = (byte) (0xff & srcPort >> 8);
124 request.match[baseOffset + SRC_PORT_OFFSET + 1] = (byte) (0xff & srcPort);
126 if (header.getDestinationPortRange() != null) {
127 // TODO (HONEYCOMB-253): port matching will not work correctly if Options are present
129 request.match[baseOffset + DST_PORT_OFFSET] = (byte) (0xff & dstPort >> 8);
130 request.match[baseOffset + DST_PORT_OFFSET + 1] = (byte) (0xff & dstPort);
132 if (ip6.getSourceIpv6Network() != null) {
134 final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network());
135 System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN);
137 if (ip6.getDestinationIpv6Network() != null) {
139 final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network());
140 System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
146 private static final int IP6_MASK_BIT_LENGTH = 128;
148 private static byte[] toByteMask(final int prefixLength) {
149 final BitSet mask = new BitSet(IP6_MASK_BIT_LENGTH);
150 mask.set(0, prefixLength, true);
151 if (prefixLength < IP6_MASK_BIT_LENGTH) {
152 mask.set(prefixLength, IP6_MASK_BIT_LENGTH, false);
154 return mask.toByteArray();
157 private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) {
158 final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]);
159 return toByteMask(prefixLength);
162 private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) {
163 final String[] split = ipv6Prefix.getValue().split("/");
164 final byte[] addressBytes;
166 addressBytes = InetAddress.getByName(split[0]).getAddress();
167 } catch (UnknownHostException e) {
168 throw new IllegalArgumentException("Invalid IP6 address", e);
170 final byte[] mask = toByteMask(Short.valueOf(split[1]));
172 for (; pos < mask.length; ++pos) {
173 addressBytes[pos] &= mask[pos];
175 // mask can be shorter that address, so we need to clear rest of the address:
176 for (; pos < addressBytes.length; ++pos) {
177 addressBytes[pos] = 0;