eb2ec8c1091fd629f101466fe7f29cfe8a0e764c
[hc2vpp.git] /
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
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:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package io.fd.honeycomb.translate.v3po.interfaces.acl.ingress;
18
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;
29
30 public interface Ip6AclTranslator {
31
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;
38     int IP6_LEN = 16;
39     int SRC_IP_OFFSET = IP_VERSION_OFFSET + 8;
40     int DST_IP_OFFSET = SRC_IP_OFFSET + IP6_LEN;
41
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;
49         }
50         if (header.getDscp() != null) {
51             aceIsEmpty = false;
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;
55         }
56         if (header.getProtocol() != null) { // Internet Protocol number
57             aceIsEmpty = false;
58             request.mask[baseOffset + IP_PROTOCOL_OFFSET] = (byte) IP_PROTOCOL_MASK;
59         }
60         if (ip6.getFlowLabel() != null) {
61             aceIsEmpty = false;
62             // bits 12-31
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;
66         }
67         if (header.getSourcePortRange() != null) {
68             log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
69         }
70         if (header.getDestinationPortRange() != null) {
71             log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
72         }
73         if (ip6.getSourceIpv6Network() != null) {
74             aceIsEmpty = false;
75             final byte[] mask = Impl.toByteMask(ip6.getSourceIpv6Network());
76             System.arraycopy(mask, 0, request.mask, baseOffset + SRC_IP_OFFSET, mask.length);
77         }
78         if (ip6.getDestinationIpv6Network() != null) {
79             aceIsEmpty = false;
80             final byte[] mask = Impl.toByteMask(ip6.getDestinationIpv6Network());
81             System.arraycopy(mask, 0, request.mask, baseOffset + DST_IP_OFFSET, mask.length);
82         }
83         return aceIsEmpty;
84     }
85
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;
93         }
94         if (header.getDscp() != null) {
95             noMatch = false;
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));
100         }
101         if (header.getProtocol() != null) { // Internet Protocol number
102             noMatch = false;
103             request.match[baseOffset + IP_PROTOCOL_OFFSET] = (byte) (IP_PROTOCOL_MASK & header.getProtocol());
104         }
105         if (ip6.getFlowLabel() != null) {
106             noMatch = false;
107             final int flowLabel = ip6.getFlowLabel().getValue().intValue();
108             // bits 12-31
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);
112         }
113         if (header.getSourcePortRange() != null) {
114             log.warn("L4 Header fields are not supported. Ignoring {}", header.getSourcePortRange());
115         }
116         if (header.getDestinationPortRange() != null) {
117             log.warn("L4 Header fields are not supported. Ignoring {}", header.getDestinationPortRange());
118         }
119         if (ip6.getSourceIpv6Network() != null) {
120             noMatch = false;
121             final byte[] match = Impl.toMatchValue(ip6.getSourceIpv6Network());
122             System.arraycopy(match, 0, request.match, baseOffset + SRC_IP_OFFSET, IP6_LEN);
123         }
124         if (ip6.getDestinationIpv6Network() != null) {
125             noMatch = false;
126             final byte[] match = Impl.toMatchValue(ip6.getDestinationIpv6Network());
127             System.arraycopy(match, 0, request.match, baseOffset + DST_IP_OFFSET, IP6_LEN);
128         }
129         return noMatch;
130     }
131
132     class Impl {
133         private static final int IP6_MASK_BIT_LENGTH = 128;
134
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);
140             }
141             return mask.toByteArray();
142         }
143
144         private static byte[] toByteMask(final Ipv6Prefix ipv6Prefix) {
145             final int prefixLength = Short.valueOf(ipv6Prefix.getValue().split("/")[1]);
146             return toByteMask(prefixLength);
147         }
148
149         private static byte[] toMatchValue(final Ipv6Prefix ipv6Prefix) {
150             final String[] split = ipv6Prefix.getValue().split("/");
151             final byte[] addressBytes;
152             try {
153                 addressBytes = InetAddress.getByName(split[0]).getAddress();
154             } catch (UnknownHostException e) {
155                 throw new IllegalArgumentException("Invalid IP6 address", e);
156             }
157             final byte[] mask = toByteMask(Short.valueOf(split[1]));
158             int pos = 0;
159             for (; pos < mask.length; ++pos) {
160                 addressBytes[pos] &= mask[pos];
161             }
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;
165             }
166             return addressBytes;
167         }
168     }
169 }