HONEYCOMB-58 - Routing Api
[honeycomb.git] / vpp-common / vpp-translate-utils / src / main / java / io / fd / honeycomb / translate / vpp / util / Ipv6Translator.java
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.vpp.util;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.base.Preconditions.checkState;
22
23 import com.google.common.net.InetAddresses;
24 import java.net.UnknownHostException;
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.stream.Collectors;
28 import javax.annotation.Nonnull;
29 import org.apache.commons.lang3.StringUtils;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
35
36 /**
37  * Trait providing logic for translation of ipv6-related data
38  */
39 public interface Ipv6Translator extends ByteDataTranslator {
40
41     /**
42      * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order
43      * as the address.
44      *
45      * @return byte array with address bytes
46      */
47     default byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) {
48         byte[] retval = new byte[16];
49
50         //splits address and add ommited zeros for easier parsing
51         List<String> segments = Arrays.asList(ipv6Addr.getValue().split(":"))
52                 .stream()
53                 .map(segment -> StringUtils.repeat('0', 4 - segment.length()) + segment)
54                 .collect(Collectors.toList());
55
56         byte index = 0;
57         for (String segment : segments) {
58
59             String firstPart = segment.substring(0, 2);
60             String secondPart = segment.substring(2);
61
62             //first part should be ommited
63             if ("00".equals(firstPart)) {
64                 index++;
65             } else {
66                 retval[index++] = ((byte) Short.parseShort(firstPart, 16));
67             }
68
69             retval[index++] = ((byte) Short.parseShort(secondPart, 16));
70         }
71
72         return retval;
73     }
74
75     /**
76      * Creates address array from address part of {@link Ipv6Prefix}
77      */
78     default byte[] ipv6AddressPrefixToArray(@Nonnull final Ipv6Prefix ipv4Prefix) {
79         checkNotNull(ipv4Prefix, "Cannot convert null prefix");
80
81         return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone(
82                 new Ipv6Address(ipv4Prefix.getValue().substring(0, ipv4Prefix.getValue().indexOf('/')))));
83     }
84
85     /**
86      * Extracts {@link Ipv6Prefix} prefix
87      */
88     default byte extractPrefix(Ipv6Prefix data) {
89         checkNotNull(data, "Cannot extract from null");
90
91         return Byte.valueOf(data.getValue().substring(data.getValue().indexOf('/') + 1));
92     }
93
94     /**
95      * Converts byte array to {@link Ipv6Prefix} with specified prefixLength
96      */
97     default Ipv6Prefix arrayToIpv6Prefix(final byte[] address, byte prefixLength) {
98         Ipv6AddressNoZone addressPart = arrayToIpv6AddressNoZone(address);
99
100         return new Ipv6Prefix(addressPart.getValue().concat("/").concat(String.valueOf(prefixLength)));
101     }
102
103     /**
104      * Parse byte array returned by VPP representing an Ipv6 address. Vpp returns IP byte arrays in reversed order.
105      *
106      * @return Ipv46ddressNoZone containing string representation of IPv6 address constructed from submitted bytes. No
107      * change in order.
108      */
109     @Nonnull
110     default Ipv6AddressNoZone arrayToIpv6AddressNoZone(@Nonnull byte[] ip) {
111         checkArgument(ip.length == 16, "Illegal array length");
112
113         try {
114             return new Ipv6AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip)));
115         } catch (UnknownHostException e) {
116             throw new IllegalArgumentException("Unable to parse ipv6", e);
117         }
118     }
119
120     /**
121      * Detects whether {@code IpAddress} is ipv6
122      */
123     default boolean isIpv6(IpAddress address) {
124         checkNotNull(address, "Address cannot be null");
125
126         checkState(!(address.getIpv4Address() == null && address.getIpv6Address() == null), "Invalid address");
127         return address.getIpv6Address() != null;
128     }
129
130     /**
131      * Parse byte array returned by VPP representing an Ipv6 address. Vpp returns IP byte arrays in natural order.
132      *
133      * @return Ipv46ddressNoZone containing string representation of IPv6 address constructed from submitted bytes. No
134      * change in order.
135      */
136     @Nonnull
137     default Ipv6AddressNoZone arrayToIpv6AddressNoZoneReversed(@Nonnull byte[] ip) {
138         checkArgument(ip.length == 16, "Illegal array length");
139
140         ip = reverseBytes(ip);
141
142         try {
143             return new Ipv6AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip)));
144         } catch (UnknownHostException e) {
145             throw new IllegalArgumentException("Unable to parse ipv6", e);
146         }
147     }
148
149
150     /**
151      * Detects whether {@code IpPrefix} is ipv6
152      */
153     default boolean isIpv6(IpPrefix address) {
154         checkNotNull(address, "Address cannot be null");
155         checkState(!(address.getIpv4Prefix() == null && address.getIpv6Prefix() == null), "Invalid address");
156         return address.getIpv6Prefix() != null;
157     }
158 }