Skip to content

Commit

Permalink
Merge pull request #14540 from opensourcerouting/feature/bgpd_handle_…
Browse files Browse the repository at this point in the history
…fqdn_capability_via_dynamic_capability

bgpd: Handle FQDN capability using dynamic capabilities
  • Loading branch information
riw777 authored Oct 24, 2023
2 parents 27a78f8 + 49d1539 commit b6b0001
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 6 deletions.
128 changes: 126 additions & 2 deletions bgpd/bgp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,8 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
uint8_t number_of_orfs = 0;
const char *capability = lookup_msg(capcode_str, capability_code,
"Unknown");
const char *hostname = cmd_hostname_get();
const char *domainname = cmd_domainname_get();

if (!peer_established(peer->connection))
return;
Expand Down Expand Up @@ -1531,11 +1533,48 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
capability, iana_afi2str(pkt_afi),
iana_safi2str(pkt_safi));
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_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_FQDN:
case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_EXT_MESSAGE:
break;
Expand Down Expand Up @@ -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,
struct capability_header *hdr,
struct peer *peer)
Expand Down Expand Up @@ -3593,11 +3715,13 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_ORF:
bgp_dynamic_capability_orf(pnt, action, hdr, peer);
break;
case CAPABILITY_CODE_FQDN:
bgp_dynamic_capability_fqdn(pnt, action, hdr, peer);
break;
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_FQDN:
case CAPABILITY_CODE_ENHE:
case CAPABILITY_CODE_EXT_MESSAGE:
break;
Expand Down
9 changes: 6 additions & 3 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -10572,7 +10572,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
/* one clear bgp command to rule them all */
DEFUN (clear_ip_bgp_all,
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
IP_STR
BGP_STR
Expand All @@ -10595,7 +10595,8 @@ DEFUN (clear_ip_bgp_all,
BGP_SOFT_IN_STR
"Push out prefix-list ORF and do inbound soft reconfig\n"
BGP_SOFT_OUT_STR
"Reset message statistics\n")
"Reset message statistics\n"
"Resend capabilities\n")
{
char *vrf = NULL;

Expand Down Expand Up @@ -10652,7 +10653,7 @@ DEFUN (clear_ip_bgp_all,
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, "in", &idx)
|| argv_find(argv, argc, "out", &idx))
Expand All @@ -10669,6 +10670,8 @@ DEFUN (clear_ip_bgp_all,
clr_type = BGP_CLEAR_SOFT_OUT;
} else if (argv_find(argv, argc, "message-stats", &idx)) {
clr_type = BGP_CLEAR_MESSAGE_STATS;
} else if (argv_find(argv, argc, "capabilities", &idx)) {
clr_type = BGP_CLEAR_CAPABILITIES;
} else
clr_type = BGP_CLEAR_SOFT_NONE;

Expand Down
13 changes: 13 additions & 0 deletions bgpd/bgpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
* it may end up freeing the doppelganger, and if this was the next node
Expand Down Expand Up @@ -8154,6 +8164,9 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
if (stype == BGP_CLEAR_MESSAGE_STATS)
peer_reset_message_stats(peer);

if (stype == BGP_CLEAR_CAPABILITIES)
peer_clear_capabilities(peer, afi, safi);

return 0;
}

Expand Down
3 changes: 2 additions & 1 deletion bgpd/bgpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -2073,7 +2073,8 @@ enum bgp_clear_type {
BGP_CLEAR_SOFT_IN,
BGP_CLEAR_SOFT_BOTH,
BGP_CLEAR_SOFT_IN_ORF_PREFIX,
BGP_CLEAR_MESSAGE_STATS
BGP_CLEAR_MESSAGE_STATS,
BGP_CLEAR_CAPABILITIES,
};

/* Macros. */
Expand Down
20 changes: 20 additions & 0 deletions doc/user/bgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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,
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:

.. clicmd:: write-quanta (1-64)
Expand Down

0 comments on commit b6b0001

Please sign in to comment.