BUG-5983: Fix wrong representation of Ip length
[bgpcep.git] / util / src / main / java / org / opendaylight / protocol / util / Ipv4Util.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.net.InetAddress;
16 import java.net.InetSocketAddress;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.List;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IetfInetUtil;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
26
27 /**
28  * Util class for creating generated Ipv4Address.
29  */
30 public final class Ipv4Util {
31     public static final int IP4_LENGTH = 4;
32     public static final int IP4_BITS_LENGTH = 32;
33     private static final Ipv4Prefix EMPTY_PREFIX = new Ipv4Prefix("0.0.0.0/0");
34
35     private Ipv4Util() {
36         throw new UnsupportedOperationException();
37     }
38
39     /**
40      * Reads from ByteBuf buffer and converts bytes to Ipv4Address.
41      *
42      * @param buffer containing Ipv4 address, starting at reader index
43      * @return Ipv4Address
44      */
45     public static Ipv4Address addressForByteBuf(final ByteBuf buffer) {
46         return IetfInetUtil.INSTANCE.ipv4AddressFor(ByteArray.readBytes(buffer, IP4_LENGTH));
47     }
48
49     /**
50      * From string ipAddress creates an InetAddress and puts it into ByteBuf.
51      * @param ipAddress Ipv4 address
52      * @return ByteBuf with filled in bytes from ipAddress
53      */
54     public static ByteBuf byteBufForAddress(final Ipv4Address ipAddress) {
55         return Unpooled.wrappedBuffer(bytesForAddress(ipAddress));
56     }
57
58     /**
59      * Converts Ipv4Address to byte array.
60      *
61      * @param address Ipv4Address to be converted
62      * @return byte array
63      */
64     public static byte[] bytesForAddress(final Ipv4Address address) {
65         return IetfInetUtil.INSTANCE.ipv4AddressBytes(address);
66     }
67
68     public static int prefixBitsToBytes(final int bits) {
69         if (bits % Byte.SIZE != 0) {
70             return (bits / Byte.SIZE) + 1;
71         }
72         return bits / Byte.SIZE;
73     }
74
75     /**
76      * Returns number of minimum bytes needed to cover all bits of prefix.
77      *
78      * @param prefix
79      * @return
80      */
81     public static int getPrefixLengthBytes(final String prefix) {
82         return prefixBitsToBytes(Ipv4Util.getPrefixLength(prefix));
83     }
84
85     /**
86      * Converts Ipv4Prefix to byte array. Prefix length at the end.
87      *
88      * @param prefix Ipv4Prefix to be converted
89      * @return byte array with prefix length at the end
90      */
91     public static byte[] bytesForPrefix(final Ipv4Prefix prefix) {
92         return IetfInetUtil.INSTANCE.ipv4PrefixToBytes(prefix);
93     }
94
95     /**
96      * Converts Ipv4Prefix to byte array. Prefix length at the beginning.
97      * Prefix bytes are trimmed from the end to match prefix length.
98      *
99      * @param prefix Ipv4Prefix to be converted
100      * @return byte array with the prefix length at the beginning
101      *
102      * @deprecated This is inefficient, refactor code to use {@link #bytesForAddress(Ipv4Address)} or
103      *             {@link ByteBufWriteUtil#writeMinimalPrefix(Ipv4Prefix, ByteBuf)}.
104      */
105     @Deprecated
106     public static byte[] bytesForPrefixBegin(final Ipv4Prefix prefix) {
107         final byte[] addrWithPrefix = bytesForPrefix(prefix);
108         return prefixedBytes(addrWithPrefix[IP4_LENGTH], addrWithPrefix);
109     }
110
111     static byte[] prefixedBytes(final byte prefixBits, final byte[] address) {
112         if (prefixBits != 0) {
113             final int prefixBytes = prefixBitsToBytes(Byte.toUnsignedInt(prefixBits));
114             final byte[] ret = new byte[prefixBytes + 1];
115             ret[0] = prefixBits;
116             System.arraycopy(address, 0, ret, 1, prefixBytes);
117             return ret;
118         } else {
119             return new byte[] { 0 };
120         }
121     }
122
123     /**
124      * Creates an Ipv4Prefix object from given byte array.
125      *
126      * @param bytes  IPv4 address
127      * @param length prefix length
128      * @return Ipv4Prefix object
129      */
130     public static Ipv4Prefix prefixForBytes(final byte[] bytes, final int length) {
131         Preconditions.checkArgument(length <= bytes.length * Byte.SIZE);
132
133         final byte[] tmp;
134         if (bytes.length != IP4_LENGTH) {
135             tmp = Arrays.copyOfRange(bytes, 0, IP4_LENGTH);
136         } else {
137             tmp = bytes;
138         }
139
140         return IetfInetUtil.INSTANCE.ipv4PrefixFor(tmp, length);
141     }
142
143     /**
144      * Creates an Ipv4Prefix object from given ByteBuf. Prefix length is assumed to
145      * be in the left most byte of the buffer.
146      *
147      * @param buf Buffer containing serialized prefix
148      * @return Ipv4Prefix object
149      */
150     public static Ipv4Prefix prefixForByteBuf(final ByteBuf buf) {
151         final int prefixLength = buf.readByte();
152         final int size = prefixLength / Byte.SIZE + ((prefixLength % Byte.SIZE == 0) ? 0 : 1);
153         final int readable = buf.readableBytes();
154         Preconditions.checkArgument(size <= readable, "Illegal length of IP prefix: %s/%s", size, readable);
155
156         final byte[] bytes = new byte[IP4_LENGTH];
157         buf.readBytes(bytes, 0, size);
158         return IetfInetUtil.INSTANCE.ipv4PrefixFor(bytes, prefixLength);
159     }
160
161     /**
162      * Creates a list of Ipv4 Prefixes from given byte array.
163      *
164      * @param bytes to be converted to List of Ipv4Prefixes.
165      * @return A list of Ipv4Prefixes
166      */
167     public static List<Ipv4Prefix> prefixListForBytes(final byte[] bytes) {
168         if (bytes.length == 0) {
169             return Collections.emptyList();
170         }
171         final List<Ipv4Prefix> list = new ArrayList<>();
172         int byteOffset = 0;
173         while (byteOffset < bytes.length) {
174             final int bitLength = UnsignedBytes.toInt(bytes[byteOffset]);
175             byteOffset += 1;
176             // if length == 0, default route will be added
177             if (bitLength == 0) {
178                 list.add(EMPTY_PREFIX);
179                 continue;
180             }
181
182             list.add(IetfInetUtil.INSTANCE.ipv4PrefixForShort(bytes, byteOffset, bitLength));
183             byteOffset += bitLength / Byte.SIZE;
184             if (bitLength % Byte.SIZE != 0) {
185                 byteOffset++;
186             }
187
188         }
189         return list;
190     }
191
192     /**
193      * Obtains prefix length from given string prefix.
194      *
195      * @param prefixValue value of prefix
196      * @return prefix length
197      */
198     protected static int getPrefixLength(final String prefixValue) {
199         final int sep = prefixValue.indexOf('/');
200         return Integer.parseInt(prefixValue.substring(sep + 1, prefixValue.length()));
201     }
202
203     /**
204      * Converts InetAddress to IpAddress.
205      *
206      * @param inetAddress
207      * @return IpAddress
208      */
209     public static IpAddress getIpAddress(final InetAddress inetAddress) {
210         return IetfInetUtil.INSTANCE.ipAddressFor(inetAddress);
211     }
212
213     /**
214      * Converts IpAddress and PortNumber to InetSocketAddress
215      *
216      * @param ipAddress
217      * @param port
218      * @return InetSocketAddress
219      */
220     public static InetSocketAddress toInetSocketAddress(final IpAddress ipAddress, final PortNumber port) {
221         final String ipString;
222         if (ipAddress.getIpv4Address() != null) {
223             ipString = ipAddress.getIpv4Address().getValue();
224         } else {
225             ipString = ipAddress.getIpv6Address().getValue();
226         }
227         return new InetSocketAddress(InetAddresses.forString(ipString), port.getValue());
228     }
229 }