From 03ee1cadd54b234ae9d481dff52ce0a445b41c06 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 29 Sep 2023 10:21:34 +0300 Subject: [PATCH 1/3] bgpd: Handle FQDN capability using dynamic capabilities Signed-off-by: Donatas Abraitis --- bgpd/bgp_packet.c | 128 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index b585591e2f69..f955c5057791 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -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; @@ -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; @@ -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) @@ -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; From f90ea076da605de22f806f12ce3e1ad89ae41ece Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 6 Oct 2023 17:41:18 +0300 Subject: [PATCH 2/3] bgpd: Add `clear bgp capabilities` command to resend some dynamic capabilities For instance, it's not possible to resend FQDN capability without resetting the session, so let's create some more elegant way to do that. Signed-off-by: Donatas Abraitis --- bgpd/bgp_vty.c | 9 ++++++--- bgpd/bgpd.c | 13 +++++++++++++ bgpd/bgpd.h | 3 ++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fca9e2ad8e3c..bce4be97259a 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -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 [ VIEWVRFNAME] [ []] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> []|in [prefix-filter]|out|message-stats>]", + "clear [ip] bgp [ VIEWVRFNAME] [ []] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> []|in [prefix-filter]|out|message-stats|capabilities>]", CLEAR_STR IP_STR BGP_STR @@ -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; @@ -10652,7 +10653,7 @@ DEFUN (clear_ip_bgp_all, clr_sort = clear_external; } - /* []|in [prefix-filter]|out|message-stats>] */ + /* []|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)) @@ -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; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 04c06b94d8ac..0a01d719687f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -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 @@ -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; } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bc2008b78ba2..22082aa52e08 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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. */ From 49d1539a703e6eb3b0dccb2a0cf80f4b6166cfe7 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Fri, 6 Oct 2023 17:56:36 +0300 Subject: [PATCH 3/3] doc: Add a new command to resend dynamic capabilities For now it includes only FQDN capability, because other capabilities can be resend using specific knobs. Signed-off-by: Donatas Abraitis --- doc/user/bgp.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 3e7efc12aa5e..43572be07e40 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -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)