summaryrefslogtreecommitdiff
path: root/bgpd/bgp_open.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_open.c')
-rw-r--r--bgpd/bgp_open.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 9fcd64bd2d..ddc8f9e8a6 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -530,6 +530,48 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
return 0;
}
+static int
+bgp_capability_enhe (struct peer *peer, struct capability_header *hdr)
+{
+ struct stream *s = BGP_INPUT (peer);
+ size_t end = stream_get_getp (s) + hdr->length;
+
+ while (stream_get_getp (s) + 6 <= end)
+ {
+ afi_t afi = stream_getw (s);
+ safi_t safi = stream_getw (s);
+ afi_t nh_afi = stream_getw (s);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s Received with value triple (afi/safi/next-hop afi): %u/%u/%u",
+ peer->host, afi, safi, nh_afi);
+
+ if (!bgp_afi_safi_valid_indices (afi, &safi))
+ return -1;
+
+ if (afi != AFI_IP || nh_afi != AFI_IP6)
+ {
+ zlog_warn ("%s Extended Next-hop capability, wrong afi/next-hop afi: %u/%u",
+ peer->host, afi, nh_afi);
+ return -1;
+ }
+
+ /* Until SAFIs other than SAFI_UNICAST are supported */
+ if (safi != SAFI_UNICAST)
+ zlog_warn ("%s Extended Next-hop capability came with unsupported SAFI: %u",
+ peer->host, safi);
+
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_RCV);
+
+ if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_ADV))
+ SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ENHE_AF_NEGO);
+ }
+
+ SET_FLAG (peer->cap, PEER_CAP_ENHE_RCV);
+
+ return 0;
+}
+
static const struct message capcode_str[] =
{
{ CAPABILITY_CODE_MP, "MultiProtocol Extensions" },
@@ -539,6 +581,7 @@ bgp_capability_hostname (struct peer *peer, struct capability_header *hdr)
{ CAPABILITY_CODE_AS4, "4-octet AS number" },
{ CAPABILITY_CODE_ADDPATH, "AddPath" },
{ CAPABILITY_CODE_DYNAMIC, "Dynamic" },
+ { CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding" },
{ CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)" },
{ CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" },
{ CAPABILITY_CODE_ORF_OLD, "ORF (Old)" },
@@ -557,6 +600,7 @@ static const size_t cap_minsizes[] =
[CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN,
[CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN,
[CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN,
+ [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN,
[CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN,
[CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry),
[CAPABILITY_CODE_HOSTNAME] = CAPABILITY_CODE_MIN_HOSTNAME_LEN,
@@ -624,6 +668,7 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
case CAPABILITY_CODE_ADDPATH:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD:
+ case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_HOSTNAME:
/* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code])
@@ -703,6 +748,10 @@ bgp_capability_parse (struct peer *peer, size_t length, int *mp_capability,
if (bgp_capability_hostname (peer, &caphdr))
return -1;
break;
+ case CAPABILITY_CODE_ENHE:
+ if (bgp_capability_enhe (peer, &caphdr))
+ return -1;
+ break;
default:
if (caphdr.code > 128)
{
@@ -1087,6 +1136,26 @@ bgp_open_capability (struct stream *s, struct peer *peer)
stream_putc (s, SAFI_MPLS_LABELED_VPN);
}
#ifdef HAVE_IPV6
+ /* Currently supporting RFC-5549 for Link-Local peering only */
+ if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE) &&
+ peer->su.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LINKLOCAL(&peer->su.sin6.sin6_addr))
+ {
+ /* RFC 5549 Extended Next Hop Encoding */
+ SET_FLAG (peer->cap, PEER_CAP_ENHE_ADV);
+ stream_putc (s, BGP_OPEN_OPT_CAP);
+ stream_putc (s, CAPABILITY_CODE_ENHE_LEN + 2);
+ stream_putc (s, CAPABILITY_CODE_ENHE);
+ stream_putc (s, CAPABILITY_CODE_ENHE_LEN);
+ /* Currently supporting for SAFI_UNICAST only */
+ SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_ADV);
+ stream_putw (s, AFI_IP);
+ stream_putw (s, SAFI_UNICAST);
+ stream_putw (s, AFI_IP6);
+
+ if (CHECK_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_RCV))
+ SET_FLAG (peer->af_cap[AFI_IP][SAFI_UNICAST], PEER_CAP_ENHE_AF_NEGO);
+ }
/* IPv6 unicast. */
if (peer->afc[AFI_IP6][SAFI_UNICAST])
{