2 * Copyright (c) 2016 Cisco and/or its affiliates.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package io.fd.honeycomb.translate.v3po.util;
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;
23 import com.google.common.base.Splitter;
24 import com.google.common.net.InetAddresses;
25 import java.net.UnknownHostException;
26 import java.util.Arrays;
27 import java.util.List;
28 import java.util.concurrent.ExecutionException;
29 import java.util.concurrent.Future;
30 import java.util.concurrent.TimeUnit;
31 import java.util.concurrent.TimeoutException;
32 import java.util.function.BiConsumer;
33 import java.util.stream.Collectors;
34 import javax.annotation.Nonnegative;
35 import javax.annotation.Nonnull;
36 import javax.annotation.Nullable;
37 import org.apache.commons.codec.DecoderException;
38 import org.apache.commons.codec.binary.Hex;
39 import org.apache.commons.lang3.StringUtils;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.openvpp.jvpp.VppBaseCallException;
50 import org.openvpp.jvpp.dto.JVppReply;
52 public final class TranslateUtils {
54 public static final Splitter COLON_SPLITTER = Splitter.on(':');
55 public static final int DEFAULT_TIMEOUT_IN_SECONDS = 5;
57 private TranslateUtils() {
60 public static <REP extends JVppReply<?>> REP getReplyForWrite(@Nonnull Future<REP> future,
61 @Nonnull final InstanceIdentifier<?> replyType)
62 throws VppBaseCallException, WriteTimeoutException {
63 return getReplyForWrite(future, replyType, DEFAULT_TIMEOUT_IN_SECONDS);
66 public static <REP extends JVppReply<?>> REP getReplyForWrite(@Nonnull Future<REP> future,
67 @Nonnull final InstanceIdentifier<?> replyType,
68 @Nonnegative final int timeoutInSeconds)
69 throws VppBaseCallException, WriteTimeoutException {
71 return getReply(future, timeoutInSeconds);
72 } catch (TimeoutException e) {
73 throw new WriteTimeoutException(replyType, e);
77 public static <REP extends JVppReply<?>> REP getReplyForRead(@Nonnull Future<REP> future,
78 @Nonnull final InstanceIdentifier<?> replyType)
79 throws VppBaseCallException, ReadTimeoutException {
80 return getReplyForRead(future, replyType, DEFAULT_TIMEOUT_IN_SECONDS);
83 public static <REP extends JVppReply<?>> REP getReplyForRead(@Nonnull Future<REP> future,
84 @Nonnull final InstanceIdentifier<?> replyType,
85 @Nonnegative final int timeoutInSeconds)
86 throws VppBaseCallException, ReadTimeoutException {
88 return getReply(future, timeoutInSeconds);
89 } catch (TimeoutException e) {
90 throw new ReadTimeoutException(replyType, e);
94 public static <REP extends JVppReply<?>> REP getReply(@Nonnull Future<REP> future)
95 throws TimeoutException, VppBaseCallException {
96 return getReply(future, DEFAULT_TIMEOUT_IN_SECONDS);
99 public static <REP extends JVppReply<?>> REP getReply(@Nonnull Future<REP> future,
100 @Nonnegative final int timeoutInSeconds)
101 throws TimeoutException, VppBaseCallException {
103 checkArgument(timeoutInSeconds > 0, "Timeout cannot be < 0");
104 return future.get(timeoutInSeconds, TimeUnit.SECONDS);
105 } catch (InterruptedException e) {
106 Thread.currentThread().interrupt();
107 throw new IllegalStateException("Interrupted", e);
108 } catch (ExecutionException e) {
109 // Execution exception could generally contains any exception
110 // when using exceptions instead of return codes just rethrow it for processing on corresponding place
111 if (e instanceof ExecutionException && (e.getCause() instanceof VppBaseCallException)) {
112 throw (VppBaseCallException) (e.getCause());
114 throw new IllegalStateException(e);
118 public static final byte[] ipAddressToArray(IpAddress address) {
119 checkNotNull(address, "Cannot resolve null adddress");
121 if (isIpv6(address)) {
122 return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone(address.getIpv6Address()));
124 return ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(address.getIpv4Address()));
129 * Creates address array from address part of {@link Ipv4Prefix}
131 public static byte[] ipv4AddressPrefixToArray(@Nonnull final Ipv4Prefix ipv4Prefix) {
132 checkNotNull(ipv4Prefix, "Cannot convert null prefix");
134 byte[] retval = new byte[4];
135 String[] address = ipv4Prefix.getValue().substring(0, ipv4Prefix.getValue().indexOf('/')).split("\\.");
137 for (int d = 0; d < 4; d++) {
138 retval[d] = (byte) (Short.parseShort(address[d]) & 0xff);
144 * Converts {@link IpAddress} to array representing {@link Ipv4Address} or {@link Ipv6Address}
146 public static byte[] ipAddressToArray(boolean isIpv6, @Nonnull IpAddress address) {
147 checkNotNull(address, "Cannot convert null Address");
150 return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone(address.getIpv6Address()));
152 return ipv4AddressNoZoneToArray(new Ipv4AddressNoZone(address.getIpv4Address()));
157 * Converts array bytes to {@link IpAddress}
160 public static IpAddress arrayToIpAddress(boolean isIpv6, byte[] ip) {
162 return new IpAddress(arrayToIpv6AddressNoZone(ip));
164 return new IpAddress(arrayToIpv4AddressNoZone(ip));
169 * Extracts {@link Ipv4Prefix} prefix
171 public static byte extractPrefix(Ipv4Prefix data) {
172 checkNotNull(data, "Cannot extract from null");
174 return Byte.valueOf(data.getValue().substring(data.getValue().indexOf('/') + 1));
178 * Converts byte array to {@link Ipv4Prefix} with specified prefixLength
180 public static Ipv4Prefix arrayToIpv4Prefix(final byte[] address, byte prefixLength) {
181 Ipv4AddressNoZone addressPart = arrayToIpv4AddressNoZone(address);
183 return new Ipv4Prefix(addressPart.getValue().concat("/").concat(String.valueOf(prefixLength)));
187 * Transform Ipv6 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order
190 * @return byte array with address bytes
192 public static byte[] ipv6AddressNoZoneToArray(@Nonnull final Ipv6AddressNoZone ipv6Addr) {
193 byte[] retval = new byte[16];
195 //splits address and add ommited zeros for easier parsing
196 List<String> segments = Arrays.asList(ipv6Addr.getValue().split(":"))
198 .map(segment -> StringUtils.repeat('0',4-segment.length())+segment)
199 .collect(Collectors.toList());
202 for (String segment : segments) {
204 String firstPart =segment.substring(0, 2);
205 String secondPart = segment.substring(2);
207 //first part should be ommited
208 if("00".equals(firstPart)){
211 retval[index++] = ((byte) Short.parseShort(firstPart, 16));
214 retval[index++] = ((byte) Short.parseShort(secondPart, 16));
221 * Creates address array from address part of {@link Ipv6Prefix}
223 public static byte[] ipv6AddressPrefixToArray(@Nonnull final Ipv6Prefix ipv4Prefix) {
224 checkNotNull(ipv4Prefix, "Cannot convert null prefix");
226 return ipv6AddressNoZoneToArray(new Ipv6AddressNoZone(
227 new Ipv6Address(ipv4Prefix.getValue().substring(0, ipv4Prefix.getValue().indexOf('/')))));
231 * Extracts {@link Ipv6Prefix} prefix
233 public static byte extractPrefix(Ipv6Prefix data) {
234 checkNotNull(data, "Cannot extract from null");
236 return Byte.valueOf(data.getValue().substring(data.getValue().indexOf('/') + 1));
240 * Converts byte array to {@link Ipv6Prefix} with specified prefixLength
242 public static Ipv6Prefix arrayToIpv6Prefix(final byte[] address, byte prefixLength) {
243 Ipv6AddressNoZone addressPart = arrayToIpv6AddressNoZone(address);
245 return new Ipv6Prefix(addressPart.getValue().concat("/").concat(String.valueOf(prefixLength)));
249 * Parse byte array returned by VPP representing an Ipv6 address. Vpp returns IP byte arrays in reversed order.
251 * @return Ipv46ddressNoZone containing string representation of IPv6 address constructed from submitted bytes. No
255 public static Ipv6AddressNoZone arrayToIpv6AddressNoZone(@Nonnull byte[] ip) {
256 checkArgument(ip.length == 16, "Illegal array length");
259 return new Ipv6AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip)));
260 } catch (UnknownHostException e) {
261 throw new IllegalArgumentException("Unable to parse ipv6", e);
267 * Parse byte array returned by VPP representing an Ipv6 address. Vpp returns IP byte arrays in natural order.
269 * @return Ipv46ddressNoZone containing string representation of IPv6 address constructed from submitted bytes. No
273 public static Ipv6AddressNoZone arrayToIpv6AddressNoZoneReversed(@Nonnull byte[] ip) {
274 checkArgument(ip.length == 16, "Illegal array length");
276 ip = reverseBytes(ip);
279 return new Ipv6AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip)));
280 } catch (UnknownHostException e) {
281 throw new IllegalArgumentException("Unable to parse ipv6", e);
286 * Converts byte array to address string ,not separated with ":"
288 public static String byteArrayToMacUnseparated(byte[] address) {
289 checkArgument(address.length == 6, "Illegal array length");
290 return Hex.encodeHexString(address);
294 * Converts byte array to address string ,separated with ":"
296 public static String byteArrayToMacSeparated(byte[] address) {
297 checkArgument(address.length == 6, "Illegal array length");
299 String unseparatedAddress = Hex.encodeHexString(address);
300 String separated = "";
302 for (int i = 0; i < unseparatedAddress.length(); i = i + 2) {
303 if (i == (unseparatedAddress.length() - 2)) {
304 separated = separated + unseparatedAddress.substring(0 + i, 2 + i);
306 separated = separated + unseparatedAddress.substring(0 + i, 2 + i) + ":";
314 * Converts MAC string to byte array
316 public static byte[] macToByteArray(String mac){
317 checkNotNull(mac,"MAC cannot be null");
319 mac = mac.replace(":","");
322 return Hex.decodeHex(mac.toCharArray());
323 } catch (DecoderException e) {
324 throw new IllegalArgumentException("Unable to convert mac",e);
329 * Detects whether {@code IpAddress} is ipv6
331 public static boolean isIpv6(IpAddress address) {
332 checkNotNull(address, "Address cannot be null");
334 checkState(!(address.getIpv4Address() == null && address.getIpv6Address() == null), "Invalid address");
335 return address.getIpv6Address() != null;
339 * Detects whether {@code IpPrefix} is ipv6
341 public static boolean isIpv6(IpPrefix address) {
342 checkNotNull(address, "Address cannot be null");
343 checkState(!(address.getIpv4Prefix() == null && address.getIpv6Prefix() == null), "Invalid address");
344 return address.getIpv6Prefix() != null;
349 * Transform Ipv4 address to a byte array acceptable by VPP. VPP expects incoming byte array to be in the same order
352 * @return byte array with address bytes
354 public static byte[] ipv4AddressNoZoneToArray(final Ipv4AddressNoZone ipv4Addr) {
355 return ipv4AddressNoZoneToArray(ipv4Addr.getValue());
358 public static byte[] ipv4AddressNoZoneToArray(final String ipv4Addr) {
359 byte[] retval = new byte[4];
360 String[] dots = ipv4Addr.split("\\.");
362 for (int d = 0; d < 4; d++) {
363 retval[d] = (byte) (Short.parseShort(dots[d]) & 0xff);
369 * Parse byte array returned by VPP representing an Ipv4 address. Vpp returns IP byte arrays in reversed order.
371 * @return Ipv4AddressNoZone containing string representation of IPv4 address constructed from submitted bytes. No
375 public static Ipv4AddressNoZone arrayToIpv4AddressNoZone(@Nonnull byte[] ip) {
376 // VPP sends ipv4 in a 16 byte array
377 if (ip.length == 16) {
378 ip = Arrays.copyOfRange(ip, 0, 4);
381 // Not reversing the byte array here!! because the IP coming from VPP is in reversed byte order
382 // compared to byte order it was submitted
383 return new Ipv4AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip)));
384 } catch (UnknownHostException e) {
385 throw new IllegalArgumentException("Unable to parse ipv4", e);
390 * Parse byte array returned by VPP representing an Ipv4 address. Vpp returns IP byte arrays in reversed order.
392 * @return Ipv4AddressNoZone containing string representation of IPv4 address constructed from submitted bytes. No
396 public static Ipv4AddressNoZone arrayToIpv4AddressNoZoneReversed(@Nonnull byte[] ip) {
397 // VPP sends ipv4 in a 16 byte array
399 if (ip.length == 16) {
400 ip = Arrays.copyOfRange(ip, 0, 4);
403 ip = reverseBytes(ip);
406 // Not reversing the byte array here!! because the IP coming from VPP is in reversed byte order
407 // compared to byte order it was submitted
408 return new Ipv4AddressNoZone(InetAddresses.toAddrString(InetAddresses.fromLittleEndianByteArray(ip)));
409 } catch (UnknownHostException e) {
410 throw new IllegalArgumentException("Unable to parse ipv4", e);
415 * Return (interned) string from byte array while removing \u0000. Strings represented as fixed length byte[] from
416 * vpp contain \u0000.
418 public static String toString(final byte[] cString) {
419 return new String(cString).replaceAll("\\u0000", "").intern();
423 * Parse string represented mac address (using ":" as separator) into a byte array
426 public static byte[] parseMac(@Nonnull final String macAddress) {
427 final List<String> parts = COLON_SPLITTER.splitToList(macAddress);
428 checkArgument(parts.size() == 6, "Mac address is expected to have 6 parts but was: %s", macAddress);
429 return parseMacLikeString(parts);
432 private static byte[] parseMacLikeString(final List<String> strings) {
433 return strings.stream().limit(6).map(TranslateUtils::parseHexByte).collect(
434 () -> new byte[strings.size()],
435 new BiConsumer<byte[], Byte>() {
440 public void accept(final byte[] bytes, final Byte aByte) {
445 throw new UnsupportedOperationException("Parallel collect not supported");
449 public static byte parseHexByte(final String aByte) {
450 return (byte) Integer.parseInt(aByte, 16);
454 * Returns 0 if argument is null or false, 1 otherwise.
456 * @param value Boolean value to be converted
457 * @return byte value equal to 0 or 1
459 public static byte booleanToByte(@Nullable final Boolean value) {
460 return value != null && value
466 * Returns Boolean.TRUE if argument is 0, Boolean.FALSE otherwise.
468 * @param value byte value to be converted
469 * @return Boolean value
470 * @throws IllegalArgumentException if argument is neither 0 nor 1
473 public static Boolean byteToBoolean(final byte value) {
475 return Boolean.FALSE;
476 } else if (value == 1) {
479 throw new IllegalArgumentException(String.format("0 or 1 was expected but was %d", value));
483 * Reverses bytes in the byte array
485 * @param bytes input array
486 * @return reversed array
488 public static byte[] reverseBytes(final byte[] bytes) {
489 final byte[] reversed = new byte[bytes.length];
491 for (byte aByte : bytes) {
492 reversed[bytes.length - i++] = aByte;