BUG-5983: Fix wrong representation of Ip length
[bgpcep.git] / util / src / main / java / org / opendaylight / protocol / util / Ipv6Util.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.protocol.util;
9
10 import com.google.common.base.Preconditions;
11 import com.google.common.net.InetAddresses;
12 import com.google.common.primitives.UnsignedBytes;
13 import io.netty.buffer.ByteBuf;
14 import io.netty.buffer.Unpooled;
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Collections;
18 import java.util.List;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IetfInetUtil;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
22
23 /**
24  * Util class for creating generated Ipv6Address.
25  */
26 public final class Ipv6Util {
27     public static final int IPV6_LENGTH = 16;
28     public static final int IPV6_BITS_LENGTH = 128;
29     private static final Ipv6Prefix EMPTY_PREFIX = new Ipv6Prefix("::/0");
30
31     private Ipv6Util() {
32         throw new UnsupportedOperationException();
33     }
34
35     /**
36      * Creates uncompressed IP Address
37      *
38      * @param ip to be uncompressed
39      * @return Ipv6Address with same, but uncompressed, value
40      */
41     public static Ipv6Address getFullForm(final Ipv6Address ip) {
42         return new Ipv6Address(InetAddresses.forString(ip.getValue()).getHostAddress());
43     }
44
45     /**
46      * Reads from ByteBuf buffer and converts bytes to Ipv6Address.
47      *
48      * @param buffer containing Ipv6 address, starting at reader index
49      * @return Ipv6Address
50      */
51     public static Ipv6Address addressForByteBuf(final ByteBuf buffer) {
52         return IetfInetUtil.INSTANCE.ipv6AddressFor(ByteArray.readBytes(buffer, IPV6_LENGTH));
53     }
54
55     /**
56      * From string ipAddress creates an InetAddress and puts it into ByteBuf.
57      * @param ipAddress Ipv6 address
58      * @return ByteBuf with filled in bytes from ipAddress
59      */
60     public static ByteBuf byteBufForAddress(final Ipv6Address ipAddress) {
61         return Unpooled.wrappedBuffer(bytesForAddress(ipAddress));
62     }
63
64     /**
65      * Converts Ipv6Address to byte array.
66      *
67      * @param address Ipv6Address to be converted
68      * @return byte array
69      */
70     public static byte[] bytesForAddress(final Ipv6Address address) {
71         return IetfInetUtil.INSTANCE.ipv6AddressBytes(address);
72     }
73
74     /**
75      * Converts Ipv6Prefix to byte array. Prefix length at the end.
76      *
77      * @param prefix Ipv6Prefix to be converted
78      * @return byte array with prefix length at the end
79      */
80     public static byte[] bytesForPrefix(final Ipv6Prefix prefix) {
81         return IetfInetUtil.INSTANCE.ipv6PrefixToBytes(prefix);
82     }
83
84     /**
85      * Converts Ipv6Prefix to byte array. Prefix length at the beginning.
86      * Prefix bytes are trimmed from the end to match prefix length.
87      *
88      * @param prefix Ipv6Prefix to be converted
89      * @return byte array with the prefix length at the beginning
90      *
91      * @deprecated This is inefficient, refactor code to use {@link #bytesForAddress(Ipv6Address)} or
92      *             {@link ByteBufWriteUtil#writeMinimalPrefix(Ipv6Prefix, ByteBuf)}.
93      */
94     @Deprecated
95     public static byte[] bytesForPrefixBegin(final Ipv6Prefix prefix) {
96         final byte[] addrWithPrefix = bytesForPrefix(prefix);
97         return Ipv4Util.prefixedBytes(addrWithPrefix[IPV6_LENGTH], addrWithPrefix);
98     }
99
100     /**
101      * Creates an Ipv6Prefix object from given byte array.
102      *
103      * @param bytes IPv6 address
104      * @param length prefix length
105      * @return Ipv6Prefix object
106      */
107     public static Ipv6Prefix prefixForBytes(final byte[] bytes, final int length) {
108         Preconditions.checkArgument(length <= bytes.length * Byte.SIZE);
109
110         final byte[] tmp;
111         if (bytes.length != IPV6_LENGTH) {
112             tmp = Arrays.copyOfRange(bytes, 0, IPV6_LENGTH);
113         } else {
114             tmp = bytes;
115         }
116
117         return IetfInetUtil.INSTANCE.ipv6PrefixFor(tmp, length);
118     }
119
120     /**
121      * Creates an Ipv6Prefix object from given ByteBuf. Prefix length is assumed to
122      * be in the left most byte of the buffer.
123      *
124      * @param buf IPv6 address
125      * @return Ipv6Prefix object
126      */
127     public static Ipv6Prefix prefixForByteBuf(final ByteBuf buf) {
128         final int prefixLength = buf.readByte();
129         final int size = prefixLength / Byte.SIZE + ((prefixLength % Byte.SIZE == 0) ? 0 : 1);
130         final int readable = buf.readableBytes();
131         Preconditions.checkArgument(size <= readable, "Illegal length of IP prefix: %s/%s", size, readable);
132
133         final byte[] bytes = new byte[IPV6_LENGTH];
134         buf.readBytes(bytes, 0, size);
135         return IetfInetUtil.INSTANCE.ipv6PrefixFor(bytes, prefixLength);
136     }
137
138     /**
139      * Creates a list of Ipv6 Prefixes from given byte array.
140      *
141      * @param bytes to be converted to List of Ipv6Prefixes.
142      * @return A List of Ipv6Prefixes
143      */
144     public static List<Ipv6Prefix> prefixListForBytes(final byte[] bytes) {
145         if (bytes.length == 0) {
146             return Collections.emptyList();
147         }
148         final List<Ipv6Prefix> list = new ArrayList<>();
149         int byteOffset = 0;
150         while (byteOffset < bytes.length) {
151             final int bitLength = UnsignedBytes.toInt(bytes[byteOffset]);
152             byteOffset += 1;
153             // if length == 0, default route will be added
154             if (bitLength == 0) {
155                 list.add(EMPTY_PREFIX);
156                 continue;
157             }
158             list.add(IetfInetUtil.INSTANCE.ipv6PrefixForShort(bytes, byteOffset, bitLength));
159             byteOffset += bitLength / Byte.SIZE;
160             if (bitLength % Byte.SIZE != 0) {
161                 byteOffset++;
162             }
163         }
164         return list;
165     }
166 }