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 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;
28 import org.slf4j.Logger;
30 public interface Ip6AclTranslator {
32 int ETHER_TYPE_OFFSET = 12; // first 14 bytes represent L2 header (2x6)
33 int IP_VERSION_OFFSET = ETHER_TYPE_OFFSET + 2;
34 int DSCP_MASK1 = 0x0f;
35 int DSCP_MASK2 = 0xc0;
36 int IP_PROTOCOL_OFFSET = IP_VERSION_OFFSET + 6;
37 int IP_PROTOCOL_MASK = 0xff;
39 int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8;
40 int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN;
42 default boolean ip6Mask(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
43 final AclIpv6HeaderFields ip6, final ClassifyAddDelTable request, final Logger log) {
44 boolean aceIsEmpty = true;
45 if (InterfaceMode.L2.equals(mode)) {
46 // in L2 mode we need to match ether type
47 request.mask[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0xff;
48 request.mask[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xff;
50 if (header.getDscp() != null) {
52 // DCSP (bits 4-9 of IP6 header)
53 request.mask[baseOffset + IP_VERSION_OFFSET] |= DSCP_MASK1;
54 request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= DSCP_MASK2;
56 if (header.getProtocol() != null) { // Internet Protocol number
58 request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
60 if (ip6.getFlowLabel() != null) {
63 request.mask[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) 0x0f;
64 request.mask[baseOffset + IP_VERSION_OFFSET + 2] = (byte) 0xff;
65 request.mask[baseOffset + IP_VERSION_OFFSET + 3] = (byte) 0xff;
67 if (header.getSourcePortRange() != null) {
68 log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
70 if (header.getDestinationPortRange() != null) {
71 log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
73 if (ip6.getSourceIpv6Network() != null) {
75 final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network());
76 System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length);
78 if (ip6.getDestinationIpv6Network() != null) {
80 final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network());
81 System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
86 default boolean ip6Match(final int baseOffset, final InterfaceMode mode, final AclIpHeaderFields header,
87 final AclIpv6HeaderFields ip6, final ClassifyAddDelSession request, final Logger log) {
88 boolean noMatch = true;
89 if (InterfaceMode.L2.equals(mode)) {
90 // match IP6 etherType (0x86dd)
91 request.match[baseOffset + ETHER_TYPE_OFFSET] = (byte) 0x86;
92 request.match[baseOffset + ETHER_TYPE_OFFSET + 1] = (byte) 0xdd;
94 if (header.getDscp() != null) {
96 final int dcsp = header.getDscp().getValue();
97 // set bits 4-9 of IP6 header:
98 request.match[baseOffset + IP_VERSION_OFFSET] |= (byte) (DSCP_MASK1 & (dcsp >> 2));
99 request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (DSCP_MASK2 & (dcsp << 6));
101 if (header.getProtocol() != null) { // Internet Protocol number
103 request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
105 if (ip6.getFlowLabel() != null) {
107 final int flowLabel = ip6.getFlowLabel().getValue().intValue();
109 request.match[baseOffset + IP_VERSION_OFFSET + 1] |= (byte) (0x0f & (flowLabel >> 16));
110 request.match[baseOffset + IP_VERSION_OFFSET + 2] = (byte) (0xff & (flowLabel >> 8));
111 request.match[baseOffset + IP_VERSION_OFFSET + 3] = (byte) (0xff & flowLabel);
113 if (header.getSourcePortRange() != null) {
114 log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
116 if (header.getDestinationPortRange() != null) {
117 log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
119 if (ip6.getSourceIpv6Network() != null) {
121 final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network());
122 System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN);
124 if (ip6.getDestinationIpv6Network() != null) {
126 final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network());
127 System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
133 private static final int IP6_MASK_BIT_LENGTH = 128;
135 private static byte[] toByteMask(final int prefixLength) {
136 final BitSet mask = new BitSet(IP6_MASK_BIT_LENGTH);
137 mask.set(0, prefixLength, true);
138 if (prefixLength < IP6_MASK_BIT_LENGTH) {
139 mask.set(prefixLength, IP6_MASK_BIT_LENGTH, false);
141 return mask.toByteArray();
144 private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) {
145 final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]);
146 return toByteMask(prefixLength);
149 private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) {
150 final String[] split = ipv6Prefix.getValue().split("/");
151 final byte[] addressBytes;
153 addressBytes = InetAddress.getByName(split[0]).getAddress();
154 } catch (UnknownHostException e) {
155 throw new IllegalArgumentException("Invalid IP6 address", e);
157 final byte[] mask = toByteMask(Short.valueOf(split[1]));
159 for (; pos < mask.length; ++pos) {
160 addressBytes[pos] &= mask[pos];
162 // mask can be shorter that address, so we need to clear rest of the address:
163 for (; pos < addressBytes.length; ++pos) {
164 addressBytes[pos] = 0;