Bump versions to 0.21.7-SNAPSHOT
[bgpcep.git] / bgp / extensions / linkstate / src / main / java / org / opendaylight / protocol / bgp / linkstate / impl / tlvs / ReachTlvParser.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.protocol.bgp.linkstate.impl.tlvs;
9
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;
22
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();
27     @VisibleForTesting
28     public static final NodeIdentifier IP_REACH_NID = NodeIdentifier.create(IP_REACHABILITY_QNAME);
29     private static final int IP_REACHABILITY = 265;
30
31     /**
32      * {@inheritDoc}
33      *
34      * <p>
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}.
40      *
41      * <p>
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.
45      */
46     // FIXME: perhaps we need a dedicated type, or just always use IPv6?
47     @Override
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));
53     }
54
55     @Override
56     public QName getTlvQName() {
57         return IP_REACHABILITY_QNAME;
58     }
59
60     @Override
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);
66         }
67     }
68
69     @Override
70     public int getType() {
71         return IP_REACHABILITY;
72     }
73
74     public static IpPrefix serializeModel(final ContainerNode prefixDesc) {
75         final var ipReach = prefixDesc.childByArg(IP_REACH_NID);
76         if (ipReach == null) {
77             return null;
78         }
79
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));
85     }
86 }