+// SPDX-License-Identifier: GPL-2.0-or-later
/* BGP open message handling
* Copyright (C) 1998, 1999 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
{CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"},
{CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"},
{CAPABILITY_CODE_ROLE, "Role"},
+ {CAPABILITY_CODE_SOFT_VERSION, "Software Version"},
{0}};
/* Minimum sizes for length field of each cap (so not inc. the header) */
[CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN,
[CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,
[CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN,
+ [CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN,
};
/* value the capability must be a multiple of.
[CAPABILITY_CODE_EXT_MESSAGE] = 1,
[CAPABILITY_CODE_LLGR] = 1,
[CAPABILITY_CODE_ROLE] = 1,
+ [CAPABILITY_CODE_SOFT_VERSION] = 1,
};
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
"capabilityErrorMultiProtocolAfi",
"L2VPN");
break;
- default:
+ case AFI_UNSPEC:
+ case AFI_MAX:
json_object_int_add(
json_cap,
"capabilityErrorMultiProtocolAfiUnknown",
"capabilityErrorMultiProtocolSafi",
"flowspec");
break;
- default:
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
json_object_int_add(
json_cap,
"capabilityErrorMultiProtocolSafiUnknown",
case AFI_L2VPN:
vty_out(vty, "AFI L2VPN, ");
break;
- default:
+ case AFI_UNSPEC:
+ case AFI_MAX:
vty_out(vty, "AFI Unknown %d, ",
ntohs(mpc.afi));
break;
case SAFI_EVPN:
vty_out(vty, "SAFI EVPN");
break;
- default:
+ case SAFI_UNSPEC:
+ case SAFI_MAX:
vty_out(vty, "SAFI Unknown %d ",
mpc.safi);
break;
}
static const struct message orf_type_str[] = {
+ {ORF_TYPE_RESERVED, "Reserved"},
{ORF_TYPE_PREFIX, "Prefixlist"},
{ORF_TYPE_PREFIX_OLD, "Prefixlist (old)"},
{0}};
switch (hdr->code) {
case CAPABILITY_CODE_ORF:
switch (type) {
+ case ORF_TYPE_RESERVED:
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %d/%d has reserved ORF type, ignoring",
+ peer->host, afi, safi);
+ break;
case ORF_TYPE_PREFIX:
break;
default:
break;
case CAPABILITY_CODE_ORF_OLD:
switch (type) {
+ case ORF_TYPE_RESERVED:
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %d/%d has reserved ORF type, ignoring",
+ peer->host, afi, safi);
+ break;
case ORF_TYPE_PREFIX_OLD:
break;
default:
return 0;
}
+static int bgp_capability_software_version(struct peer *peer,
+ struct capability_header *hdr)
+{
+ struct stream *s = BGP_INPUT(peer);
+ char str[BGP_MAX_SOFT_VERSION + 1];
+ size_t end = stream_get_getp(s) + hdr->length;
+ uint8_t len;
+
+ SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV);
+
+ len = stream_getc(s);
+ if (stream_get_getp(s) + len > end) {
+ flog_warn(
+ EC_BGP_CAPABILITY_INVALID_DATA,
+ "%s: Received malformed Software Version capability from peer %s",
+ __func__, peer->host);
+ return -1;
+ }
+
+ if (len) {
+ stream_get(str, s, len);
+ str[len] = '\0';
+
+ XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
+
+ peer->soft_version = XSTRDUP(MTYPE_BGP_SOFT_VERSION, str);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s sent Software Version: %s", peer->host,
+ peer->soft_version);
+ }
+
+ return 0;
+}
+
/**
* Parse given capability.
* XXX: This is reading into a stream, but not using stream API
case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_EXT_MESSAGE:
case CAPABILITY_CODE_ROLE:
+ case CAPABILITY_CODE_SOFT_VERSION:
/* Check length. */
if (caphdr.length < cap_minsizes[caphdr.code]) {
zlog_info(
case CAPABILITY_CODE_ROLE:
ret = bgp_capability_role(peer, &caphdr);
break;
+ case CAPABILITY_CODE_SOFT_VERSION:
+ ret = bgp_capability_software_version(peer, &caphdr);
+ break;
default:
if (caphdr.code > 128) {
/* We don't send Notification for unknown vendor
return 0;
}
-static int bgp_auth_parse(struct peer *peer, size_t length)
-{
- bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
- BGP_NOTIFY_OPEN_AUTH_FAILURE);
- return -1;
-}
-
static bool strict_capability_same(struct peer *peer)
{
int i, j;
zlog_debug(
"%s rcvd OPEN w/ optional parameter type %u (%s) len %u",
peer->host, opt_type,
- opt_type == BGP_OPEN_OPT_AUTH
- ? "Authentication"
- : opt_type == BGP_OPEN_OPT_CAP
- ? "Capability"
- : "Unknown",
+ opt_type == BGP_OPEN_OPT_CAP ? "Capability"
+ : "Unknown",
opt_length);
switch (opt_type) {
- case BGP_OPEN_OPT_AUTH:
- ret = bgp_auth_parse(peer, opt_length);
- break;
case BGP_OPEN_OPT_CAP:
ret = bgp_capability_parse(peer, opt_length,
mp_capability, &error);
iana_safi_t pkt_safi = IANA_SAFI_UNICAST;
as_t local_as;
uint8_t afi_safi_count = 0;
- int adv_addpath_tx = 0;
+ bool adv_addpath_tx = false;
/* Non-Ext OP Len. */
cp = stream_get_endp(s);
* will use it is
* configured */
if (peer->addpath_type[afi][safi] != BGP_ADDPATH_NONE)
- adv_addpath_tx = 1;
+ adv_addpath_tx = true;
+
+ /* If we have enabled labeled unicast, we MUST check
+ * against unicast SAFI because addpath IDs are
+ * allocated under unicast SAFI, the same as the RIB
+ * is managed in unicast SAFI.
+ */
+ if (safi == SAFI_LABELED_UNICAST)
+ if (peer->addpath_type[afi][SAFI_UNICAST] !=
+ BGP_ADDPATH_NONE)
+ adv_addpath_tx = true;
}
}
SET_FLAG(flags, BGP_ADDPATH_TX);
SET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_ADV);
+ if (safi == SAFI_LABELED_UNICAST)
+ SET_FLAG(
+ peer->af_cap[afi][SAFI_UNICAST],
+ PEER_CAP_ADDPATH_AF_TX_ADV);
} else {
UNSET_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ADDPATH_AF_TX_ADV);
bgp_peer_send_gr_capability(s, peer, ext_opt_params);
bgp_peer_send_llgr_capability(s, peer, ext_opt_params);
+ /* Software Version capability
+ * An implementation is REQUIRED Extended Optional Parameters
+ * Length for BGP OPEN Message support as defined in [RFC9072].
+ * The inclusion of the Software Version Capability is OPTIONAL.
+ * If an implementation supports the inclusion of the capability,
+ * the implementation MUST include a configuration switch to enable
+ * or disable its use, and that switch MUST be off by default.
+ */
+ if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION) ||
+ peer->sort == BGP_PEER_IBGP) {
+ SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV);
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ rcapp = stream_get_endp(s);
+ ext_opt_params ? stream_putw(s, 0)
+ : stream_putc(s, 0); /* Capability Length */
+ stream_putc(s, CAPABILITY_CODE_SOFT_VERSION);
+ capp = stream_get_endp(s);
+ stream_putc(s, 0); /* dummy placeholder len */
+
+ /* The Capability Length SHOULD be no greater than 64.
+ * This is the limit to allow other capabilities as much
+ * space as they require.
+ */
+ len = strlen(cmd_software_version_get());
+ if (len > BGP_MAX_SOFT_VERSION)
+ len = BGP_MAX_SOFT_VERSION;
+
+ stream_putc(s, len);
+ stream_put(s, cmd_software_version_get(), len);
+
+ /* Software Version capability Len. */
+ len = stream_get_endp(s) - rcapp - 1;
+ ext_opt_params ? stream_putw_at(s, rcapp, len - 1)
+ : stream_putc_at(s, rcapp, len);
+
+ /* Total Capability Len. */
+ len = stream_get_endp(s) - capp - 1;
+ stream_putc_at(s, capp, len);
+
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Sending Software Version cap, value: %s",
+ peer->host, cmd_software_version_get());
+ }
+
/* Total Opt Parm Len. */
len = stream_get_endp(s) - cp - 1;