*/
package org.opendaylight.bgp.concepts;
+import com.google.common.base.Preconditions;
import io.netty.buffer.ByteBuf;
import org.opendaylight.protocol.util.ByteBufWriteUtil;
import org.opendaylight.protocol.util.Ipv4Util;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RdAs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RdIpv4;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RdTwoOctetAs;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisher;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.RouteDistinguisherBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Utility class for of RouteDistinguisher serialization and parsing.
* https://tools.ietf.org/html/rfc4364#section-4.2
*/
public final class RouteDistinguisherUtil {
+ private static final Logger LOG = LoggerFactory.getLogger(RouteDistinguisherUtil.class);
+
+ private enum RD_TYPE {
+ AS_2BYTE(0),
+ IPV4(1),
+ AS_4BYTE(2),
+ INVALID(-1);
+
+ public final int value;
+
+ RD_TYPE(int val) {
+ value = val;
+ }
+
+ public static RD_TYPE valueOf(final int value) {
+ for (RD_TYPE type : values()) {
+ if (type.value == value) {
+ return type;
+ }
+ }
+ return INVALID;
+ }
+ }
- private static final int IPV4_TYPE = 1;
- private static final int AS_4BYTE_TYPE = 2;
private static final String SEPARATOR = ":";
public static final int RD_LENGTH = 8;
/**
* Serializes route distinguisher according to type and writes into ByteBuf.
*
- * @param distinquisher
+ * @param distinguisher
* @param byteAggregator
*/
- public static void serializeRouteDistinquisher(final RouteDistinguisher distinquisher, final ByteBuf byteAggregator) {
- if (distinquisher.getRdAs() != null) {
- final String[] values = distinquisher.getRdAs().getValue().split(SEPARATOR);
- byteAggregator.writeShort(AS_4BYTE_TYPE);
+ public static void serializeRouteDistinquisher(final RouteDistinguisher distinguisher, final ByteBuf byteAggregator) {
+ Preconditions.checkNotNull(distinguisher);
+ Preconditions.checkState(byteAggregator != null && byteAggregator.isWritable(RD_LENGTH), "Cannot write Route Distinguisher to provided buffer.");
+ if (distinguisher.getRdTwoOctetAs() != null) {
+ final String[] values = distinguisher.getRdTwoOctetAs().getValue().split(SEPARATOR);
+ byteAggregator.writeShort(RD_TYPE.AS_2BYTE.value);
+ ByteBufWriteUtil.writeUnsignedShort(Integer.parseInt(values[1]), byteAggregator);
+ final long assignedNumber = Integer.parseUnsignedInt(values[2]);
+ ByteBufWriteUtil.writeUnsignedInt(assignedNumber, byteAggregator);
+ } else if (distinguisher.getRdAs() != null) {
+ final String[] values = distinguisher.getRdAs().getValue().split(SEPARATOR);
+ byteAggregator.writeShort(RD_TYPE.AS_4BYTE.value);
final long admin = Integer.parseUnsignedInt(values[0]);
ByteBufWriteUtil.writeUnsignedInt(admin, byteAggregator);
ByteBufWriteUtil.writeUnsignedShort(Integer.parseInt(values[1]), byteAggregator);
- } else if (distinquisher.getRdIpv4() != null) {
- final String[] values = distinquisher.getRdIpv4().getValue().split(SEPARATOR);
+ } else if (distinguisher.getRdIpv4() != null) {
+ final String[] values = distinguisher.getRdIpv4().getValue().split(SEPARATOR);
final Ipv4Address ip = new Ipv4Address(values[0]);
- byteAggregator.writeShort(IPV4_TYPE);
+ byteAggregator.writeShort(RD_TYPE.IPV4.value);
ByteBufWriteUtil.writeIpv4Address(ip, byteAggregator);
ByteBufWriteUtil.writeUnsignedShort(Integer.parseInt(values[1]), byteAggregator);
+ } else {
+ LOG.warn("Unable to serialize Route Distinguisher. Invalid RD value found. RD={}", distinguisher);
}
}
* @return RouteDistinguisher
*/
public static RouteDistinguisher parseRouteDistinguisher(final ByteBuf buffer) {
+ Preconditions.checkState(buffer != null && buffer.isReadable(RD_LENGTH), "Cannot read Route Distinguisher from provided buffer.");
final int type = buffer.readUnsignedShort();
+ final RD_TYPE rdType = RD_TYPE.valueOf(type);
final StringBuilder routeDistiguisher = new StringBuilder();
- switch (type) {
- case IPV4_TYPE:
+ switch (rdType) {
+ case AS_2BYTE:
+ routeDistiguisher.append(type);
+ routeDistiguisher.append(SEPARATOR);
+ routeDistiguisher.append(buffer.readUnsignedShort());
+ routeDistiguisher.append(SEPARATOR);
+ routeDistiguisher.append(buffer.readUnsignedInt());
+ return new RouteDistinguisher(new RdTwoOctetAs(routeDistiguisher.toString()));
+ case IPV4:
routeDistiguisher.append(Ipv4Util.addressForByteBuf(buffer).getValue());
routeDistiguisher.append(SEPARATOR);
routeDistiguisher.append(buffer.readUnsignedShort());
return new RouteDistinguisher(new RdIpv4(routeDistiguisher.toString()));
- case AS_4BYTE_TYPE:
+ case AS_4BYTE:
routeDistiguisher.append(buffer.readUnsignedInt());
routeDistiguisher.append(SEPARATOR);
routeDistiguisher.append(buffer.readUnsignedShort());
return new RouteDistinguisher(new RdAs(routeDistiguisher.toString()));
default:
- break;
+ // now that this RD type is not supported, we want to read the remain 6 bytes
+ // in order to get the byte index correct
+ for (int i = 0; i < 6; i++) {
+ routeDistiguisher.append("0x").append(Integer.toHexString(buffer.readByte() & 0xFF)).append(" ");
+ }
+ LOG.debug("Invalid Route Distinguisher: type={}, rawRouteDistinguisherValue={}", type, routeDistiguisher.toString());
+ throw new IllegalArgumentException("Invalid Route Distinguisher type " + type);
+ }
+ }
+
+ public static RouteDistinguisher parseRouteDistinguisher(final String str) {
+ return str == null ? null : RouteDistinguisherBuilder.getDefaultInstance(str);
+ }
+
+ public static RouteDistinguisher parseRouteDistinguisher(final Object obj) {
+ if (obj instanceof String) {
+ return RouteDistinguisherBuilder.getDefaultInstance((String) obj);
+ } else if (obj instanceof RouteDistinguisher) {
+ return (RouteDistinguisher) obj;
+ } else {
+ return null;
}
- return null;
}
}
*/
public class RouteDistinguisherBuilder {
+ private static final Pattern RD_TWO_OCTET_AS =
+ Pattern.compile("0:"
+ + "([0-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|"
+ + "[1-9][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9][0-9]|"
+ + "[1-9][0-9][0-9][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|"
+ + "[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|[1-3][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|"
+ + "4[0-1][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|42[0-8][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|"
+ + "429[0-3][0-9][0-9][0-9][0-9][0-9][0-9]|4294[0-8][0-9][0-9][0-9][0-9][0-9]|"
+ + "42949[0-5][0-9][0-9][0-9][0-9]|429496[0-6][0-9][0-9][0-9]|4294967[0-1][0-9][0-9]|"
+ + "42949672[0-8][0-9]|429496729[0-5])"
+ + ":"
+ + "([0-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|"
+ + "[1-5][0-9][0-9][0-9][0-9]|6[0-4][0-9][0-9][0-9]|"
+ + "65[0-4][0-9][0-9]|655[0-2][0-9]|6553[0-5])");
+
private static final Pattern RD_IPV4 =
Pattern.compile("((([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}"
+ "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]))"
}
public static RouteDistinguisher getDefaultInstance(final java.lang.String defaultValue) {
- if (RD_IPV4.matcher(defaultValue).matches()) {
+ if (RD_TWO_OCTET_AS.matcher(defaultValue).matches()) {
+ return new RouteDistinguisher((new RdTwoOctetAs(defaultValue)));
+ } else if (RD_IPV4.matcher(defaultValue).matches()) {
return new RouteDistinguisher(new RdIpv4(defaultValue));
} else if (RD_AS.matcher(defaultValue).matches()) {
return new RouteDistinguisher(new RdAs(defaultValue));
typedef route-distinguisher {
reference "https://tools.ietf.org/html/rfc4364#section-4.2";
type union {
+ type rd-two-octet-as;
type rd-ipv4;
type rd-as;
}
}
+ typedef rd-two-octet-as {
+ type string {
+ /* 2B AS : 4B number */
+ pattern '0:'
+ + '([0-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|'
+ + '[1-5][0-9][0-9][0-9][0-9]|6[0-4][0-9][0-9][0-9]|'
+ + '65[0-4][0-9][0-9]|655[0-2][0-9]|6553[0-5])'
+ + ':'
+ + '([0-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|'
+ + '[1-9][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9][0-9]|'
+ + '[1-9][0-9][0-9][0-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|'
+ + '[1-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|[1-3][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|'
+ + '4[0-1][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|42[0-8][0-9][0-9][0-9][0-9][0-9][0-9][0-9]|'
+ + '429[0-3][0-9][0-9][0-9][0-9][0-9][0-9]|4294[0-8][0-9][0-9][0-9][0-9][0-9]|'
+ + '42949[0-5][0-9][0-9][0-9][0-9]|429496[0-6][0-9][0-9][0-9]|4294967[0-1][0-9][0-9]|'
+ + '42949672[0-8][0-9]|429496729[0-5])';
+ }
+ }
+
typedef rd-ipv4 {
type string {
/* IPv4 : 2B number */
public class RouteDistinguisherUtilTest {
private static final String IP_ADDRESS = "1.2.3.4";
+ private static final String IP_PORT = "10";
private static final String ADMIN = "55";
+ private static final String ASSIGNED_NUMBER = "65535";
+ private static final byte[] AS_2B_BYTES = { 0, 0, 0, 55, 0, 0, (byte)0xff, (byte)0xff};
private static final byte[] IP_BYTES = { 0, 1, 1, 2, 3, 4, 0, 10 };
- private static final byte[] AS_4B_BYTES = { 0, 2, 0,0, 0, 55, (byte)0xff, (byte)0xff};
+ private static final byte[] AS_4B_BYTES = { 0, 2, 0, 0, 0, 55, (byte)0xff, (byte)0xff};
+ private static final byte[] INVALID_RD_TYPE_BYTES = { 0, 3, 0, 0, 0, 55, (byte)0xff, (byte)0xff};
private static final char SEPARATOR = ':';
+ @Test
+ public void testAs2BRouteDistinguisher() {
+ final RouteDistinguisher expected = createRouteDistinguisher(0, ADMIN, ASSIGNED_NUMBER);
+ final RouteDistinguisher parsed = RouteDistinguisherUtil.parseRouteDistinguisher(Unpooled.copiedBuffer(AS_2B_BYTES));
+ assertEquals(expected.getRdTwoOctetAs(), parsed.getRdTwoOctetAs());
+ final ByteBuf byteAggregator = Unpooled.buffer(AS_2B_BYTES.length);
+ RouteDistinguisherUtil.serializeRouteDistinquisher(expected, byteAggregator);
+ assertArrayEquals(AS_2B_BYTES, byteAggregator.array());
+ assertEquals("0" + SEPARATOR + ADMIN + SEPARATOR + ASSIGNED_NUMBER, parsed.getRdTwoOctetAs().getValue());
+ }
+
@Test
public void testIpv4RouteDistinguisher() {
- final RouteDistinguisher expected = createRouteDistinguisher(1, 10L, IP_ADDRESS);
+ final RouteDistinguisher expected = createRouteDistinguisher(1, IP_ADDRESS, IP_PORT);
final RouteDistinguisher parsed = RouteDistinguisherUtil.parseRouteDistinguisher(Unpooled.copiedBuffer(IP_BYTES));
assertEquals(expected.getRdIpv4(), parsed.getRdIpv4());
final ByteBuf byteAggregator = Unpooled.buffer(IP_BYTES.length);
RouteDistinguisherUtil.serializeRouteDistinquisher(expected, byteAggregator);
assertArrayEquals(IP_BYTES, byteAggregator.array());
+ assertEquals(IP_ADDRESS + SEPARATOR + IP_PORT, parsed.getRdIpv4().getValue());
}
@Test
public void testAs4BRouteDistinguisher() {
- final RouteDistinguisher expected = createRouteDistinguisher(2, 65535L, ADMIN);
+ final RouteDistinguisher expected = createRouteDistinguisher(2, ADMIN, ASSIGNED_NUMBER);
final RouteDistinguisher parsed = RouteDistinguisherUtil.parseRouteDistinguisher(Unpooled.copiedBuffer(AS_4B_BYTES));
assertEquals(expected.getRdAs(), parsed.getRdAs());
final ByteBuf byteAggregator = Unpooled.buffer(AS_4B_BYTES.length);
RouteDistinguisherUtil.serializeRouteDistinquisher(expected, byteAggregator);
assertArrayEquals(AS_4B_BYTES, byteAggregator.array());
+ assertEquals(ADMIN + SEPARATOR + ASSIGNED_NUMBER, parsed.getRdAs().getValue());
+ }
+
+ @Test
+ public void testParseRouteDistinguisher() {
+ final RouteDistinguisher expected = RouteDistinguisherUtil.parseRouteDistinguisher(ADMIN + SEPARATOR + ASSIGNED_NUMBER);
+ final RouteDistinguisher parsed = RouteDistinguisherUtil.parseRouteDistinguisher(Unpooled.copiedBuffer(AS_4B_BYTES));
+ assertEquals(expected.getRdAs(), parsed.getRdAs());
+
+ final RouteDistinguisher expectedRD = RouteDistinguisherUtil.parseRouteDistinguisher(expected);
+ assertEquals(expectedRD.getRdAs(), parsed.getRdAs());
+
+ final RouteDistinguisher expectedObj = RouteDistinguisherUtil.parseRouteDistinguisher((Object) (ADMIN + SEPARATOR + ASSIGNED_NUMBER));
+ assertEquals(expectedObj.getRdAs(), parsed.getRdAs());
}
@Test(expected=UnsupportedOperationException.class)
}
}
- private RouteDistinguisher createRouteDistinguisher(final int type, final long assignedNumberSubfield, final String administratorSubfield) {
+ @Test(expected=IllegalArgumentException.class)
+ public void testInvalidRDType() throws Throwable {
+ RouteDistinguisherUtil.parseRouteDistinguisher(Unpooled.copiedBuffer(INVALID_RD_TYPE_BYTES));
+ }
+
+ /**
+ * Create 4-octet AS RD or IPv4 RD, 2-octet AS RD cannot be created with this function
+ * @param administratorSubfield
+ * @param assignedNumberSubfield
+ * @return
+ */
+ private RouteDistinguisher createRouteDistinguisher(final int type, final String administratorSubfield, final String assignedNumberSubfield) {
final StringBuffer routeDistiguisher = new StringBuffer();
+ if (type == 0) {
+ routeDistiguisher.append(type).append(SEPARATOR);
+ }
routeDistiguisher.append(administratorSubfield);
routeDistiguisher.append(SEPARATOR);
routeDistiguisher.append(assignedNumberSubfield);
return RouteDistinguisherBuilder.getDefaultInstance(routeDistiguisher.toString());
}
-
}