#include "memory.h"
#include "queue.h"
+#include "lib/json.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
inforation at each peer. */
void
-bgp_capability_vty_out (struct vty *vty, struct peer *peer)
+bgp_capability_vty_out (struct vty *vty, struct peer *peer, u_char use_json, json_object *json_neigh)
{
char *pnt;
char *end;
struct capability_mp_data mpc;
struct capability_header *hdr;
+ json_object *json_cap = NULL;
+
+ if (use_json)
+ json_cap = json_object_new_object();
pnt = peer->notify.data;
end = pnt + peer->notify.length;
if (hdr->code == CAPABILITY_CODE_MP)
{
- vty_out (vty, " Capability error for: Multi protocol ");
-
- switch (ntohs (mpc.afi))
- {
- case AFI_IP:
- vty_out (vty, "AFI IPv4, ");
- break;
- case AFI_IP6:
- vty_out (vty, "AFI IPv6, ");
- break;
- default:
- vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
- break;
- }
- switch (mpc.safi)
- {
- case SAFI_UNICAST:
- vty_out (vty, "SAFI Unicast");
- break;
- case SAFI_MULTICAST:
- vty_out (vty, "SAFI Multicast");
- break;
- case SAFI_MPLS_LABELED_VPN:
- vty_out (vty, "SAFI MPLS-labeled VPN");
- break;
- default:
- vty_out (vty, "SAFI Unknown %d ", mpc.safi);
- break;
- }
- vty_out (vty, "%s", VTY_NEWLINE);
- }
+ if (use_json)
+ {
+ switch (ntohs (mpc.afi))
+ {
+ case AFI_IP:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "IPv4");
+ break;
+ case AFI_IP6:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolAfi", "IPv6");
+ break;
+ default:
+ json_object_int_add(json_cap, "capabilityErrorMultiProtocolAfiUnknown", ntohs (mpc.afi));
+ break;
+ }
+ switch (mpc.safi)
+ {
+ case SAFI_UNICAST:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "unicast");
+ break;
+ case SAFI_MULTICAST:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "multicast");
+ break;
+ case SAFI_MPLS_LABELED_VPN:
+ json_object_string_add(json_cap, "capabilityErrorMultiProtocolSafi", "MPLS-labeled VPN");
+ break;
+ default:
+ json_object_int_add(json_cap, "capabilityErrorMultiProtocolSafiUnknown", mpc.safi);
+ break;
+ }
+ }
+ else
+ {
+ vty_out (vty, " Capability error for: Multi protocol ");
+ switch (ntohs (mpc.afi))
+ {
+ case AFI_IP:
+ vty_out (vty, "AFI IPv4, ");
+ break;
+ case AFI_IP6:
+ vty_out (vty, "AFI IPv6, ");
+ break;
+ default:
+ vty_out (vty, "AFI Unknown %d, ", ntohs (mpc.afi));
+ break;
+ }
+ switch (mpc.safi)
+ {
+ case SAFI_UNICAST:
+ vty_out (vty, "SAFI Unicast");
+ break;
+ case SAFI_MULTICAST:
+ vty_out (vty, "SAFI Multicast");
+ break;
+ case SAFI_MPLS_LABELED_VPN:
+ vty_out (vty, "SAFI MPLS-labeled VPN");
+ break;
+ default:
+ vty_out (vty, "SAFI Unknown %d ", mpc.safi);
+ break;
+ }
+ vty_out (vty, "%s", VTY_NEWLINE);
+ }
+ }
else if (hdr->code >= 128)
- vty_out (vty, " Capability error: vendor specific capability code %d",
- hdr->code);
+ {
+ if (use_json)
+ json_object_int_add(json_cap, "capabilityErrorVendorSpecificCapabilityCode", hdr->code);
+ else
+ vty_out (vty, " Capability error: vendor specific capability code %d",
+ hdr->code);
+ }
else
- vty_out (vty, " Capability error: unknown capability code %d",
- hdr->code);
-
+ {
+ if (use_json)
+ json_object_int_add(json_cap, "capabilityErrorUnknownCapabilityCode", hdr->code);
+ else
+ vty_out (vty, " Capability error: unknown capability code %d",
+ hdr->code);
+ }
pnt += hdr->length + 2;
}
+ if (use_json)
+ json_object_object_add(json_neigh, "capabilityErrors", json_cap);
}
static void
struct capability_mp_data mpc;
struct stream *s = BGP_INPUT (peer);
+ /* Verify length is 4 */
+ if (hdr->length != 4)
+ {
+ zlog_warn("MP Cap: Received invalid length %d, non-multiple of 4",
+ hdr->length);
+ return -1;
+ }
+
bgp_capability_mp_data (s, &mpc);
if (bgp_debug_neighbor_events(peer))
zlog_info ("%s ORF Capability entry length error,"
" Cap length %u, num %u",
peer->host, hdr->length, entry.num);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
int restart_bit = 0;
size_t end = stream_get_getp (s) + caphdr->length;
+ /* Verify length is a multiple of 4 */
+ if ((caphdr->length-2) % 4)
+ {
+ zlog_warn("Restart Cap: Received invalid length %d, non-multiple of 4",
+ caphdr->length);
+ return -1;
+ }
+
SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV);
restart_flag_time = stream_getw(s);
if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT))
{
if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
- " Ignore the Graceful Restart capability",
+ " Ignore the Graceful Restart capability for this AFI/SAFI",
peer->host, afi, safi);
}
else if (!peer->afc[afi][safi])
return 0;
}
+/* Unlike other capability parsing routines, this one returns 0 on error */
static as_t
bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)
{
SET_FLAG (peer->cap, PEER_CAP_ADDPATH_RCV);
+ /* Verify length is a multiple of 4 */
+ if (hdr->length % 4)
+ {
+ zlog_warn("Add Path: Received invalid length %d, non-multiple of 4",
+ hdr->length);
+ return -1;
+ }
+
while (stream_get_getp (s) + 4 <= end)
{
afi_t afi = stream_getw (s);
(send_receive & BGP_ADDPATH_TX) ? ", transmit" : "");
if (!bgp_afi_safi_valid_indices (afi, &safi))
- return -1;
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s Addr-family %d/%d(afi/safi) not supported."
+ " Ignore the Addpath Attribute for this AFI/SAFI",
+ peer->host, afi, safi);
+ continue;
+ }
+ else if (!peer->afc[afi][safi])
+ {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug ("%s Addr-family %d/%d(afi/safi) not enabled."
+ " Ignore the AddPath capability for this AFI/SAFI",
+ peer->host, afi, safi);
+ continue;
+ }
if (send_receive & BGP_ADDPATH_RX)
SET_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_RCV);
return 0;
}
-static const struct message capcode_str[] =
+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;
+
+ /* Verify length is a multiple of 4 */
+ if (hdr->length % 6)
+ {
+ zlog_warn("Extended NH: Received invalid length %d, non-multiple of 6",
+ hdr->length);
+ return -1;
+ }
+
+ 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" },
{ CAPABILITY_CODE_REFRESH, "Route Refresh" },
{ 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)" },
[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),
};
size_t start;
u_char *sp = stream_pnt (s);
struct capability_header caphdr;
-
+
+ ret = 0;
/* We need at least capability code and capability length. */
if (stream_get_getp(s) + 2 > end)
{
zlog_info ("%s Capability length error (< header)", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
if (start + caphdr.length > end)
{
zlog_info ("%s Capability length error (< length)", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
case CAPABILITY_CODE_ADDPATH:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD:
+ case CAPABILITY_CODE_ENHE:
/* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code])
{
LOOKUP (capcode_str, caphdr.code),
caphdr.length,
(unsigned) cap_minsizes[caphdr.code]);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
/* we deliberately ignore unknown codes, see below */
memcpy (*error, sp, caphdr.length + 2);
*error += caphdr.length + 2;
}
+ ret = 0; /* Don't return error for this */
}
}
break;
break;
case CAPABILITY_CODE_ORF:
case CAPABILITY_CODE_ORF_OLD:
- if (bgp_capability_orf_entry (peer, &caphdr))
- return -1;
+ ret = bgp_capability_orf_entry (peer, &caphdr);
break;
case CAPABILITY_CODE_RESTART:
- if (bgp_capability_restart (peer, &caphdr))
- return -1;
+ ret = bgp_capability_restart (peer, &caphdr);
break;
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD:
* for the value really, only error case.
*/
if (!bgp_capability_as4 (peer, &caphdr))
- return -1;
+ ret = -1;
break;
case CAPABILITY_CODE_ADDPATH:
- if (bgp_capability_addpath (peer, &caphdr))
- return -1;
+ ret = bgp_capability_addpath (peer, &caphdr);
+ break;
+ case CAPABILITY_CODE_ENHE:
+ ret = bgp_capability_enhe (peer, &caphdr);
break;
default:
if (caphdr.code > 128)
*error += caphdr.length + 2;
}
}
+
+ if (ret < 0)
+ {
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ return -1;
+ }
if (stream_get_getp(s) != (start + caphdr.length))
{
if (stream_get_getp(s) > (start + caphdr.length))
if (STREAM_READABLE(s) < 2)
{
zlog_info ("%s Option length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
if (STREAM_READABLE (s) < opt_length)
{
zlog_info ("%s Option length error", peer->host);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0);
+ bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
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])
{