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.protocol.bgp.linkstate.impl.tlvs;
10 import com.google.common.annotations.VisibleForTesting;
11 import io.netty.buffer.ByteBuf;
12 import org.opendaylight.protocol.bgp.linkstate.spi.LinkstateTlvParser;
13 import org.opendaylight.protocol.util.Ipv4Util;
14 import org.opendaylight.protocol.util.Ipv6Util;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.linkstate.rev200120.linkstate.object.type.prefix._case.PrefixDescriptors;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
21 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
23 public final class ReachTlvParser implements LinkstateTlvParser.LinkstateTlvSerializer<IpPrefix>,
24 LinkstateTlvParser<IpPrefix> {
25 public static final QName IP_REACHABILITY_QNAME = QName.create(PrefixDescriptors.QNAME,
26 "ip-reachability-information").intern();
28 public static final NodeIdentifier IP_REACH_NID = NodeIdentifier.create(IP_REACHABILITY_QNAME);
29 private static final int IP_REACHABILITY = 265;
35 * IP Reachability TLV serves to convey both an IPV4 or an IPV6 prefix as per
36 * <a href="https://datatracker.ietf.org/doc/html/rfc7752#section-3.2.3.2">RFC7752 Section 3.2.3.2</a>. However, the
37 * Length of the IP Reachability TLV could not be used to distinguish the two types of prefixes as it will be the
38 * same: for example {@code byteBuffer == [24][192][168][01]} could be parsed as IPv4 prefix {@code 192.168.1.0/24}
39 * or as IPv6 prefix {@code c0a8:100::/24}.
42 * Thus, we could just verify if the length is greater than 4 bytes. In this case, it is certain that the prefix is
43 * IPv6. For a length less than or equal to 4 bytes, the parser assumes that the prefix is IPv4. In addition, the
44 * probability that an IS-IS domain advertises an IPv6 prefix with a length lower than /32 is very low.
46 // FIXME: perhaps we need a dedicated type, or just always use IPv6?
48 public IpPrefix parseTlvBody(final ByteBuf value) {
49 // Get address length to determine if it is an IPv4 or an IPv6 prefix
50 final int length = value.readableBytes() - 1;
51 return length <= Ipv4Util.IP4_LENGTH ? new IpPrefix(Ipv4Util.prefixForByteBuf(value))
52 : new IpPrefix(Ipv6Util.prefixForByteBuf(value));
56 public QName getTlvQName() {
57 return IP_REACHABILITY_QNAME;
61 public void serializeTlvBody(final IpPrefix tlv, final ByteBuf body) {
62 if (tlv.getIpv4Prefix() != null) {
63 Ipv4Util.writeMinimalPrefix(tlv.getIpv4Prefix(), body);
64 } else if (tlv.getIpv6Prefix() != null) {
65 Ipv6Util.writeMinimalPrefix(tlv.getIpv6Prefix(), body);
70 public int getType() {
71 return IP_REACHABILITY;
74 public static IpPrefix serializeModel(final ContainerNode prefixDesc) {
75 final var ipReach = prefixDesc.childByArg(IP_REACH_NID);
76 if (ipReach == null) {
80 final String prefix = (String) ipReach.body();
81 // Get the prefix length from the string to determine if it is an IPv4 or an IPv6 prefix
82 final int length = Ipv4Util.getPrefixLengthBytes(prefix);
83 return length <= Ipv4Util.IP4_LENGTH ? new IpPrefix(new Ipv4Prefix(prefix))
84 : new IpPrefix(new Ipv6Prefix(prefix));