2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.bgp.concepts;
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.VisibleForTesting;
14 import io.netty.buffer.ByteBuf;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.eclipse.jdt.annotation.Nullable;
17 import org.opendaylight.protocol.util.Ipv4Util;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RdAs;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RdIpv4;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RdTwoOctetAs;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteDistinguisher;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev200120.RouteDistinguisherBuilder;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
25 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
30 * Utility class for of RouteDistinguisher serialization and parsing.
31 * https://tools.ietf.org/html/rfc4364#section-4.2
33 public final class RouteDistinguisherUtil {
34 public static final int RD_LENGTH = 8;
36 private static final Logger LOG = LoggerFactory.getLogger(RouteDistinguisherUtil.class);
38 static final char SEPARATOR = ':';
40 // Route descriptor types
41 private static final int RD_AS_2BYTE = 0;
42 private static final int RD_IPV4 = 1;
43 private static final int RD_AS_4BYTE = 2;
45 private RouteDistinguisherUtil() {
50 * Serializes route distinguisher according to type and writes into ByteBuf.
52 public static void serializeRouteDistinquisher(final RouteDistinguisher distinguisher,
53 final ByteBuf byteAggregator) {
54 requireNonNull(distinguisher);
55 checkState(byteAggregator != null && byteAggregator.isWritable(RD_LENGTH),
56 "Cannot write Route Distinguisher to provided buffer.");
57 if (distinguisher.getRdTwoOctetAs() != null) {
58 serialize(byteAggregator, distinguisher.getRdTwoOctetAs());
59 } else if (distinguisher.getRdAs() != null) {
60 serialize(byteAggregator, distinguisher.getRdAs());
61 } else if (distinguisher.getRdIpv4() != null) {
62 serialize(byteAggregator, distinguisher.getRdIpv4());
64 LOG.warn("Unable to serialize Route Distinguisher. Invalid RD value found. RD={}", distinguisher);
68 private static void serialize(final ByteBuf buf, final RdAs as) {
69 final String value = as.getValue();
70 final int first = findSeparator(value, 0);
71 checkNoColon(value, first);
73 buf.writeShort(RD_AS_4BYTE);
74 buf.writeInt(Integer.parseUnsignedInt(value.substring(0, first)));
75 buf.writeShort(Integer.parseUnsignedInt(value.substring(first + 1)));
78 private static void serialize(final ByteBuf buf, final RdTwoOctetAs as) {
79 final String value = as.getValue();
80 final int first = findSeparator(value, 0) + 1;
81 final int second = findSeparator(value, first);
82 checkNoColon(value, second);
84 buf.writeShort(RD_AS_2BYTE);
85 buf.writeShort(Integer.parseUnsignedInt(value.substring(first, second)));
86 buf.writeInt(Integer.parseUnsignedInt(value.substring(second + 1)));
89 private static void serialize(final ByteBuf buf, final RdIpv4 ipv4) {
90 final String value = ipv4.getValue();
91 final int first = findSeparator(value, 0);
92 checkNoColon(value, first);
94 buf.writeShort(RD_IPV4);
95 buf.writeBytes(Ipv4Util.bytesForAddress(new Ipv4AddressNoZone(value.substring(0, first))));
96 buf.writeShort(Integer.parseUnsignedInt(value.substring(first + 1)));
99 private static int findSeparator(final String str, final int fromIndex) {
100 final int found = str.indexOf(SEPARATOR, fromIndex);
101 checkState(found != -1, "Invalid route distinguiser %s", str);
105 private static void checkNoColon(final String str, final int lastIndex) {
106 checkState(str.indexOf(SEPARATOR, lastIndex + 1) == -1, "Invalid route distinguiser %s", str);
110 * Parses three types of route distinguisher from given ByteBuf.
112 public static @NonNull RouteDistinguisher parseRouteDistinguisher(final ByteBuf buffer) {
113 checkState(buffer != null && buffer.isReadable(RD_LENGTH),
114 "Cannot read Route Distinguisher from provided buffer.");
115 final int type = buffer.readUnsignedShort();
118 return new RouteDistinguisher(new RdTwoOctetAs(new StringBuilder()
121 .append(buffer.readUnsignedShort())
123 .append(buffer.readUnsignedInt())
126 return new RouteDistinguisher(new RdIpv4(new StringBuilder()
127 .append(Ipv4Util.addressForByteBuf(buffer).getValue())
129 .append(buffer.readUnsignedShort())
132 return new RouteDistinguisher(new RdAs(new StringBuilder()
133 .append(buffer.readUnsignedInt())
135 .append(buffer.readUnsignedShort())
138 // now that this RD type is not supported, we want to read the remain 6 bytes
139 // in order to get the byte index correct
140 final var sb = new StringBuilder();
141 for (int i = 0; i < 6; i++) {
142 sb.append("0x").append(Integer.toHexString(buffer.readByte() & 0xFF)).append(' ');
144 LOG.debug("Invalid Route Distinguisher: type={}, rawRouteDistinguisherValue={}", type, sb);
145 throw new IllegalArgumentException("Invalid Route Distinguisher type " + type);
149 public static @Nullable RouteDistinguisher parseRouteDistinguisher(final String str) {
150 return str == null ? null : RouteDistinguisherBuilder.getDefaultInstance(str);
153 public static @Nullable RouteDistinguisher parseRouteDistinguisher(final Object obj) {
154 if (obj instanceof String str) {
155 return RouteDistinguisherBuilder.getDefaultInstance(str);
156 } else if (obj instanceof RouteDistinguisher rd) {
163 public static @Nullable RouteDistinguisher extractRouteDistinguisher(final DataContainerNode route,
164 final NodeIdentifier rdNid) {
165 final var rdNode = route.childByArg(rdNid);
166 return rdNode == null ? null : parseRouteDistinguisher(rdNode.body());