2 * Copyright (c) 2015 Brocade, Communications Systems, Inc
3 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
10 package org.opendaylight.openflowplugin.openflow.md.core.sal.convertor;
12 import com.google.common.base.Splitter;
13 import io.netty.buffer.ByteBufUtil;
14 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Address;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
18 import java.util.Iterator;
19 import com.google.common.collect.Iterators;
20 import java.util.Arrays;
21 import java.net.UnknownHostException;
22 import java.net.Inet6Address;
23 import java.net.Inet4Address;
24 import java.net.InetAddress;
25 import com.google.common.net.InetAddresses;
26 import com.google.common.base.Preconditions;
30 * Created by Martin Bobak <mbobak@cisco.com> on 5.3.2015.
31 * v6 routines added by Anton Ivanov on 14.6.2015
33 public final class IpConversionUtil {
35 public static final String PREFIX_SEPARATOR = "/";
36 public static final Splitter PREFIX_SPLITTER = Splitter.on('/');
37 final private static int INADDR4SZ = 4;
38 final private static int INADDR6SZ = 16;
39 final private static int INT16SZ = 2;
41 private IpConversionUtil() {
42 throw new IllegalStateException("This class should not be instantiated.");
45 public static Iterator<String> splitToParts(final Ipv4Prefix ipv4Prefix) {
46 return PREFIX_SPLITTER.split(ipv4Prefix.getValue()).iterator();
49 public static Iterator<String> splitToParts(final Ipv4Address ipv4Address) {
50 /* Invalid (Ab)use of ip address as prefix!!! */
51 String [] tempPrefix = {ipv4Address.getValue(), "32"};
52 return Iterators.forArray(tempPrefix);
55 public static Iterator<String> splitToParts(final Ipv6Prefix ipv6Prefix) {
56 return PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
59 public static Iterator<String> splitToParts(final Ipv6Address ipv6Address) {
60 /* Invalid (Ab)use of ip address as prefix!!! */
61 String [] tempPrefix = {ipv6Address.getValue(), "128"};
62 return Iterators.forArray(tempPrefix);
66 /* This forest of functions has a purpose:
68 * 1. There are multiple coding styles around the plugin, this is necessary in order to have
69 * one mechanism to convert them all, one mechanism to find them...
70 * 2. I hope that one day yangtools will actually deliver code fit for purpose in a packet
71 * processing application (presently it is not. When this happens, these can be optimized
72 * for "side-load" of pre-vetted data. Example. IP Address (v4 or v6) is prevetted left of the
73 * prefix. It should be loadable into Prefix without _RERUNNING_ 100ms+ of regexps. When (and if)
74 * that happens, it will be a simple fix here without chasing it across the whole plugin.
77 public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address){
78 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + 32);
81 public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, String mask){
83 * Ipv4Address has already validated the address part of the prefix,
84 * It is mandated to comply to the same regexp as the address
85 * There is absolutely no point rerunning additional checks vs this
86 * Note - there is no canonical form check here!!!
88 if (null != mask && !mask.equals("")) {
89 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + mask);
91 return new Ipv4Prefix(ipv4Address.getValue() + PREFIX_SEPARATOR + "32");
95 public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, int intmask){
96 return createPrefix(ipv4Address, "" + intmask);
99 public static Ipv4Prefix createPrefix(Ipv4Address ipv4Address, byte [] bytemask){
100 return createPrefix(ipv4Address, "" + countBits(bytemask));
103 public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address){
104 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + 128);
107 public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, String mask){
109 * Ipv6Address has already validated the address part of the prefix,
110 * It is mandated to comply to the same regexp as the address
111 * There is absolutely no point rerunning additional checks vs this
112 * Note - there is no canonical form check here!!!
114 if (null != mask && !mask.equals("")) {
115 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + mask);
117 return new Ipv6Prefix(ipv6Address.getValue() + PREFIX_SEPARATOR + "128");
121 public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, int intmask){
122 return createPrefix(ipv6Address, "" + intmask);
125 public static Ipv6Prefix createPrefix(Ipv6Address ipv6Address, byte [] bytemask){
127 * Ipv4Address has already validated the address part of the prefix,
128 * It is mandated to comply to the same regexp as the address
129 * There is absolutely no point rerunning additional checks vs this
130 * Note - there is no canonical form check here!!!
132 return createPrefix(ipv6Address, "" + countBits(bytemask));
134 public static Integer extractPrefix(Ipv4Prefix ipv4Prefix) {
135 Iterator<String> addressParts = splitToParts(ipv4Prefix);
137 Integer retval = null;
138 if (addressParts.hasNext()) {
139 retval = Integer.parseInt(addressParts.next());
144 public static Integer extractPrefix(Ipv6Prefix ipv6Prefix) {
145 Iterator<String> addressParts = splitToParts(ipv6Prefix);
147 Integer retval = null;
148 if (addressParts.hasNext()) {
149 retval = Integer.parseInt(addressParts.next());
154 public static Integer extractPrefix(Ipv4Address ipv4Prefix) {
158 public static Integer extractPrefix(Ipv6Address ipv6Prefix) {
164 * Read all of the following before you touch any v6 code or decide to
165 * optimize it by invoking a "simple" Guava call
167 * Java IPv6 is fundamentally broken and Google libraries do not fix it.
168 * 1. Java will allways implicitly rewrite v4 mapped into v6 as a v4 address
169 * and there is absolutely no way to override this behaviour
170 * 2. Guava libraries cannot parse non-canonical IPv6. They will throw an
171 * exception. Even if they did, they re-use the same broken java code
174 * This is why we have to parse v6 by ourselves.
176 * The following conversion code is based on inet_cidr_pton_ipv6 in NetBSD
178 * The original BSD code is licensed under standard BSD license. While we
179 * are not obliged to provide an attribution, credit where credit is due.
180 * As far as why it is similar to Sun's sun.net.util please ask Sun why
181 * their code has the same variable names, comments and code flow.
187 * Convert Ipv6Address object to a valid Canonical v6 address in byte format
189 * @param ipv6Address - v6 Address object
190 * @return - byte array of size 16. Last byte contains netmask
194 public static byte[] canonicalBinaryV6Address(Ipv6Address ipv6Address) {
196 * Do not modify this routine to take direct strings input!!!
197 * Key checks have been removed based on the assumption that
198 * the input is validated via regexps in Ipv6Prefix()
201 String [] address = (ipv6Address.getValue()).split("%");
207 /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
211 char[] src = address[0].toCharArray();
213 byte[] dst = new byte[INADDR6SZ];
215 int src_length = src.length;
220 /* Leading :: requires some special handling. */
222 /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
223 * We will derive our code from BSD. Shakespear always sounds better
224 * in original Clingon. So does Dilbert.
228 Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
236 while (i < src_length) {
238 int chval = Character.digit(ch, 16);
240 /* Business as usual - ipv6 address digit.
241 * We can remove all checks from the original BSD code because
242 * the regexp has already verified that we are not being fed
243 * anything bigger than 0xffff between the separators.
258 /* no need to check separator position validity - regexp does that */
263 /* removed overrun check - the regexp checks for valid data */
265 dst[j++] = (byte) ((val >> 8) & 0xff);
266 dst[j++] = (byte) (val & 0xff);
272 /* frankenstein - v4 attached to v6, mixed notation */
274 if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
276 /* this has passed the regexp so it is fairly safe to parse it
277 * straight away. As v4 addresses do not suffer from the same
278 * defficiencies as the java v6 implementation we can invoke it
279 * straight away and be done with it
282 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
284 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
286 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
288 byte[] v4addr = _inet_form.getAddress();
290 for (int k = 0; k < INADDR4SZ; k++) {
291 dst[j++] = v4addr[k];
296 /* removed parser exit on ivalid char - no need to do it, regexp checks it */
299 Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
300 dst[j++] = (byte) ((val >> 8) & 0xff);
301 dst[j++] = (byte) (val & 0xff);
307 Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
308 for (i = 1; i <= n; i++) {
309 dst[INADDR6SZ - i] = dst[colonp + n - i];
310 dst[colonp + n - i] = 0;
315 Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
320 static public String byteArrayV6AddressToString (byte [] _binary_form) throws UnknownHostException{
321 /* DO NOT DIY!!! - InetAddresses will actually print correct canonical
322 * zero compressed form.
324 return InetAddresses.toAddrString(InetAddress.getByAddress(_binary_form));
328 static private int nextNibble(int mask) {
335 return 0xff << (8 - mask);
339 * Convert Ipv6Prefix object to a valid Canonical v6 prefix in byte format
341 * @param ipv6Prefix - v6 prefix object
342 * @return - byte array of size 16 + 1. Last byte contains netmask
346 public static byte[] canonicalBinaryV6Prefix(Ipv6Prefix ipv6Prefix) {
348 * Do not modify this routine to take direct strings input!!!
349 * Key checks have been removed based on the assumption that
350 * the input is validated via regexps in Ipv6Prefix()
355 String [] address = null;
357 boolean valid = true;
359 address = (ipv6Prefix.getValue()).split("/");
361 mask = Integer.parseInt(address[1]);
365 } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
369 Preconditions.checkArgument(valid, "Supplied netmask in %s is invalid", ipv6Prefix.getValue());
376 /* Isn't it fun - the above variable names are the same in BSD and Sun sources */
380 char[] src = address[0].toCharArray();
382 byte[] dst = new byte[INADDR6SZ + 1];
386 int src_length = src.length;
391 /* Leading :: requires some special handling. */
393 /* Isn't it fun - the above comment is again the same in BSD and Sun sources,
394 * We will derive our code from BSD. Shakespear always sounds better
395 * in original Clingon. So does Dilbert.
399 Preconditions.checkArgument(src[++i] == ':', "Invalid v6 address");
407 while (i < src_length) {
409 int chval = Character.digit(ch, 16);
411 /* Business as usual - ipv6 address digit.
412 * We can remove all checks from the original BSD code because
413 * the regexp has already verified that we are not being fed
414 * anything bigger than 0xffff between the separators.
429 /* no need to check separator position validity - regexp does that */
434 /* removed overrun check - the regexp checks for valid data */
439 /* stop parsing if we are past the mask */
443 dst[j] = (byte) ((val >> 8) & nextNibble(m)); j++; m = m - 8;
446 /* stop parsing if we are past the mask */
450 dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
456 /* frankenstein - v4 attached to v6, mixed notation */
458 if (ch == '.' && ((j + INADDR4SZ) <= INADDR6SZ)) {
460 /* this has passed the regexp so it is fairly safe to parse it
461 * straight away. As v4 addresses do not suffer from the same
462 * defficiencies as the java v6 implementation we can invoke it
463 * straight away and be done with it
466 Preconditions.checkArgument(j != (INADDR6SZ - INADDR4SZ - 1), "Invalid v4 in v6 mapping");
468 InetAddress _inet_form = InetAddresses.forString(address[0].substring(curtok, src_length));
470 Preconditions.checkArgument(_inet_form instanceof Inet4Address);
472 byte[] v4addr = _inet_form.getAddress();
474 for (int k = 0; k < INADDR4SZ; k++) {
475 dst[j++] = v4addr[k];
480 /* removed parser exit on ivalid char - no need to do it, regexp checks it */
483 Preconditions.checkArgument(j + INT16SZ <= INADDR6SZ, "Overrun in v6 parsing, should not occur");
484 dst[j] = (byte) ((val >> 8) & nextNibble(m)) ; j++; m = m - 8;
485 dst[j] = (byte) (val & nextNibble(m)); j++; m = m - 8;
488 if ((j < INADDR6SZ) && (m < 0)) {
490 for (i = j; i < INADDR6SZ; i++) {
498 Preconditions.checkArgument(j != INADDR6SZ, "Overrun in v6 parsing, should not occur");
499 for (i = 1; i <= n; i++) {
500 dst[INADDR6SZ - i] = dst[colonp + n - i];
501 dst[colonp + n - i] = 0;
505 Preconditions.checkArgument(j == INADDR6SZ, "Overrun in v6 parsing, should not occur");
508 dst[INADDR6SZ] = (byte) mask;
513 * Print a v6 prefix in byte array + 1 notation
515 * @param _binary_form - prefix, in byte [] form, last byte is netmask
519 static public String byteArrayV6PrefixToString(byte [] _binary_form) throws UnknownHostException {
520 /* NO DIY!!! - InetAddresses will actually print correct canonical
521 * zero compressed form
523 StringBuilder sb = new java.lang.StringBuilder();
524 /* Yang RFC specifies that the normalized form is RFC 5952, note - java
525 * core type is not RFC compliant, guava is.
528 InetAddresses.toAddrString(
529 InetAddress.getByAddress(
530 Arrays.copyOfRange(_binary_form, 0, INADDR6SZ)
535 sb.append(_binary_form[INADDR6SZ] & 0xff);
536 return sb.toString();
541 * Canonicalize a v6 prefix while in binary form
543 * @param _prefix - prefix, in byte [] form
544 * @param mask - mask - number of bits
547 static public void canonicalizeIpv6Prefix(byte [] _prefix, int mask) {
549 for (int i=0; i < INADDR6SZ; i++) {
550 _prefix[i] = (byte) (_prefix[i] & nextNibble(mask));
555 public static byte[] convertIpv6PrefixToByteArray(int prefix) {
556 byte[] mask = new byte[16];
557 for (int count = 0; count < 16; count++) {
558 mask[count] = (byte) nextNibble(prefix);
564 public static Ipv6Address extractIpv6Address(final Ipv6Prefix ipv6Prefix) {
565 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
566 return new Ipv6Address(addressParts.next());
569 public static Integer extractIpv6Prefix(final Ipv6Prefix ipv6Prefix) {
570 Iterator<String> addressParts = PREFIX_SPLITTER.split(ipv6Prefix.getValue()).iterator();
573 Integer prefix = null;
574 if (addressParts.hasNext()) {
575 prefix = Integer.parseInt(addressParts.next());
580 private static int toInt(byte b) {
581 return b < 0 ? b + 256 : b;
584 public static int countBits(byte[] mask) {
586 for (byte b : mask) {
587 netmask += Integer.bitCount(toInt(b));