Merge pull request #14540 from opensourcerouting/feature/bgpd_handle_fqdn_capability_via_dynamic_capability

bgpd: Handle FQDN capability using dynamic capabilities
This commit is contained in:
Russ White 2023-10-24 06:23:32 -04:00 committed by GitHub
commit b6b0001a4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 167 additions and 6 deletions

View File

@ -1218,6 +1218,8 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
uint8_t number_of_orfs = 0; uint8_t number_of_orfs = 0;
const char *capability = lookup_msg(capcode_str, capability_code, const char *capability = lookup_msg(capcode_str, capability_code,
"Unknown"); "Unknown");
const char *hostname = cmd_hostname_get();
const char *domainname = cmd_domainname_get();
if (!peer_established(peer->connection)) if (!peer_established(peer->connection))
return; return;
@ -1531,11 +1533,48 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
capability, iana_afi2str(pkt_afi), capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi)); iana_safi2str(pkt_safi));
break; break;
case CAPABILITY_CODE_FQDN:
if (hostname) {
SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV);
stream_putc(s, action);
stream_putc(s, CAPABILITY_CODE_FQDN);
cap_len = stream_get_endp(s);
stream_putc(s, 0); /* Capability Length */
len = strlen(hostname);
if (len > BGP_MAX_HOSTNAME)
len = BGP_MAX_HOSTNAME;
stream_putc(s, len);
stream_put(s, hostname, len);
if (domainname) {
len = strlen(domainname);
if (len > BGP_MAX_HOSTNAME)
len = BGP_MAX_HOSTNAME;
stream_putc(s, len);
stream_put(s, domainname, len);
} else
stream_putc(s, 0);
len = stream_get_endp(s) - cap_len - 1;
stream_putc_at(s, cap_len, len);
if (bgp_debug_neighbor_events(peer))
zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s",
peer,
action == CAPABILITY_ACTION_SET
? "Advertising"
: "Removing",
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
}
break;
case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR: case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_FQDN:
case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_EXT_MESSAGE: case CAPABILITY_CODE_EXT_MESSAGE:
break; break;
@ -3233,6 +3272,89 @@ static void bgp_dynamic_capability_orf(uint8_t *pnt, int action,
} }
} }
static void bgp_dynamic_capability_fqdn(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
{
uint8_t *data = pnt + 3;
uint8_t *end = data + hdr->length;
char str[BGP_MAX_HOSTNAME + 1] = {};
uint8_t len;
if (action == CAPABILITY_ACTION_SET) {
/* hostname */
if (data + 1 > end) {
zlog_err("%pBP: Received invalid FQDN capability (host name length)",
peer);
return;
}
len = *data;
if (data + len > end) {
zlog_err("%pBP: Received invalid FQDN capability length (host name) %d",
peer, hdr->length);
return;
}
data++;
if (len > BGP_MAX_HOSTNAME) {
memcpy(&str, data, BGP_MAX_HOSTNAME);
str[BGP_MAX_HOSTNAME] = '\0';
} else if (len) {
memcpy(&str, data, len);
str[len] = '\0';
}
data += len;
if (len) {
str[len] = '\0';
XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
peer->hostname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
}
if (data + 1 > end) {
zlog_err("%pBP: Received invalid FQDN capability (domain name length)",
peer);
return;
}
/* domainname */
len = *data;
if (data + len > end) {
zlog_err("%pBP: Received invalid FQDN capability length (domain name) %d",
peer, len);
return;
}
data++;
if (len > BGP_MAX_HOSTNAME) {
memcpy(&str, data, BGP_MAX_HOSTNAME);
str[BGP_MAX_HOSTNAME] = '\0';
} else if (len) {
memcpy(&str, data, len);
str[len] = '\0';
}
data += len;
if (len) {
str[len] = '\0';
XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
}
SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV);
} else {
UNSET_FLAG(peer->cap, PEER_CAP_HOSTNAME_RCV);
XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
}
}
static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action, static void bgp_dynamic_capability_llgr(uint8_t *pnt, int action,
struct capability_header *hdr, struct capability_header *hdr,
struct peer *peer) struct peer *peer)
@ -3593,11 +3715,13 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_ORF: case CAPABILITY_CODE_ORF:
bgp_dynamic_capability_orf(pnt, action, hdr, peer); bgp_dynamic_capability_orf(pnt, action, hdr, peer);
break; break;
case CAPABILITY_CODE_FQDN:
bgp_dynamic_capability_fqdn(pnt, action, hdr, peer);
break;
case CAPABILITY_CODE_REFRESH: case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4: case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR: case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_FQDN:
case CAPABILITY_CODE_ENHE: case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_EXT_MESSAGE: case CAPABILITY_CODE_EXT_MESSAGE:
break; break;

View File

@ -10572,7 +10572,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
/* one clear bgp command to rule them all */ /* one clear bgp command to rule them all */
DEFUN (clear_ip_bgp_all, DEFUN (clear_ip_bgp_all,
clear_ip_bgp_all_cmd, clear_ip_bgp_all_cmd,
"clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]", "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats|capabilities>]",
CLEAR_STR CLEAR_STR
IP_STR IP_STR
BGP_STR BGP_STR
@ -10595,7 +10595,8 @@ DEFUN (clear_ip_bgp_all,
BGP_SOFT_IN_STR BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n" "Push out prefix-list ORF and do inbound soft reconfig\n"
BGP_SOFT_OUT_STR BGP_SOFT_OUT_STR
"Reset message statistics\n") "Reset message statistics\n"
"Resend capabilities\n")
{ {
char *vrf = NULL; char *vrf = NULL;
@ -10652,7 +10653,7 @@ DEFUN (clear_ip_bgp_all,
clr_sort = clear_external; clr_sort = clear_external;
} }
/* [<soft [<in|out>]|in [prefix-filter]|out|message-stats>] */ /* [<soft [<in|out>]|in [prefix-filter]|out|message-stats|capabilities>] */
if (argv_find(argv, argc, "soft", &idx)) { if (argv_find(argv, argc, "soft", &idx)) {
if (argv_find(argv, argc, "in", &idx) if (argv_find(argv, argc, "in", &idx)
|| argv_find(argv, argc, "out", &idx)) || argv_find(argv, argc, "out", &idx))
@ -10669,6 +10670,8 @@ DEFUN (clear_ip_bgp_all,
clr_type = BGP_CLEAR_SOFT_OUT; clr_type = BGP_CLEAR_SOFT_OUT;
} else if (argv_find(argv, argc, "message-stats", &idx)) { } else if (argv_find(argv, argc, "message-stats", &idx)) {
clr_type = BGP_CLEAR_MESSAGE_STATS; clr_type = BGP_CLEAR_MESSAGE_STATS;
} else if (argv_find(argv, argc, "capabilities", &idx)) {
clr_type = BGP_CLEAR_CAPABILITIES;
} else } else
clr_type = BGP_CLEAR_SOFT_NONE; clr_type = BGP_CLEAR_SOFT_NONE;

View File

@ -8046,6 +8046,16 @@ static void peer_reset_message_stats(struct peer *peer)
} }
} }
/* Helper function to resend some BGP capabilities that are uncontrolled.
* For instance, FQDN capability, that can't be turned off, but let's say
* we changed the hostname, we need to resend it.
*/
static void peer_clear_capabilities(struct peer *peer, afi_t afi, safi_t safi)
{
bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_FQDN,
CAPABILITY_ACTION_SET);
}
/* /*
* If peer clear is invoked in a loop for all peers on the BGP instance, * If peer clear is invoked in a loop for all peers on the BGP instance,
* it may end up freeing the doppelganger, and if this was the next node * it may end up freeing the doppelganger, and if this was the next node
@ -8154,6 +8164,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
if (stype == BGP_CLEAR_MESSAGE_STATS) if (stype == BGP_CLEAR_MESSAGE_STATS)
peer_reset_message_stats(peer); peer_reset_message_stats(peer);
if (stype == BGP_CLEAR_CAPABILITIES)
peer_clear_capabilities(peer, afi, safi);
return 0; return 0;
} }

View File

@ -2073,7 +2073,8 @@ enum bgp_clear_type {
BGP_CLEAR_SOFT_IN, BGP_CLEAR_SOFT_IN,
BGP_CLEAR_SOFT_BOTH, BGP_CLEAR_SOFT_BOTH,
BGP_CLEAR_SOFT_IN_ORF_PREFIX, BGP_CLEAR_SOFT_IN_ORF_PREFIX,
BGP_CLEAR_MESSAGE_STATS BGP_CLEAR_MESSAGE_STATS,
BGP_CLEAR_CAPABILITIES,
}; };
/* Macros. */ /* Macros. */

View File

@ -3938,6 +3938,26 @@ The following are available in the top level *enable* mode:
Clear BGP message statistics for a specified peer or for all peers, Clear BGP message statistics for a specified peer or for all peers,
optionally filtered by activated address-family and sub-address-family. optionally filtered by activated address-family and sub-address-family.
.. clicmd:: clear bgp [ipv4|ipv6] [unicast] PEER|\* capabilities
Clear specific BGP capabilities for a specified peer or for all peers. This
includes such capabilities like FQDN capability, that can't be controlled by
any other configuration knob.
For example, if you want to change the FQDN, you MUST reset the BGP session
in order to send a new FQDN capability to the peer. This command allows you
to resend FQDN capability without resetting the session.
.. code-block:: frr
hostname bgp-new.example.com
clear bgp 10.10.10.1 capabilities
.. note::
Changing the hostname is possible only when connected to the specific daemon.
If you change the hostname via ``vtysh``, it won't be changed.
The following are available in the ``router bgp`` mode: The following are available in the ``router bgp`` mode:
.. clicmd:: write-quanta (1-64) .. clicmd:: write-quanta (1-64)