This is an implementation of draft-walton-bgp-hostname-capability-02. It's implemented since quite some time for FRR and in datacenter, this gives a nice output to avoid using IP addresses.
Currently, it is always enabled. The hostname is retrieved from uname(2) and not configurable. The domain name is never set nor displayed. I don't think being able to set the hostname is very important. I don't think the domain name is useful. However, maybe the capability should not be enabled by default. Also, the case where the capability is supported but hostname is empty is handled as if the capability was not supported. I think this is not worth handling such an edge case. The RFC doesn't say if hostname is optional or not. The return code of uname(2) is not checked, but I think this is not bound to happen and if it happens, this is handled nicely by disabling the capability. The draft is expired but I hope a second implementation could allow to revive it. Output from BIRD: Local capabilities Multiprotocol AF announced: ipv6 Route refresh Graceful restart 4-octet AS numbers Enhanced refresh Long-lived graceful restart Hostname: bird2 Neighbor capabilities Multiprotocol AF announced: ipv6 Route refresh Graceful restart 4-octet AS numbers ADD-PATH RX: ipv6 TX: Hostname: frr1 Output from FRR: Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt bird1(2001:db8::11) 4 65000 548 495 0 0 0 00:03:06 0 0 bird2(2001:db8::12) 4 65000 281 256 0 0 0 00:01:49 0 0 frr2(2001:db8::22) 4 65000 501 501 0 0 0 00:24:56 0 0 Signed-off-by: Vincent Bernat <vinc...@bernat.ch> --- proto/bgp/bgp.c | 3 +++ proto/bgp/bgp.h | 2 ++ proto/bgp/config.Y | 1 + proto/bgp/packets.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 302d026c0103..d4c15f0538b1 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -2415,6 +2415,9 @@ bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps) bgp_show_afis(-1006, " AF supported:", afl1, afn1); bgp_show_afis(-1006, " AF preserved:", afl2, afn2); } + + if (*caps->hostname) + cli_msg(-1006, " Hostname: %s", caps->hostname); } static void diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index dd7dc28fd03d..3a99bc9667b5 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -98,6 +98,7 @@ struct bgp_config { int enable_refresh; /* Enable local support for route refresh [RFC 2918] */ int enable_as4; /* Enable local support for 4B AS numbers [RFC 6793] */ int enable_extended_messages; /* Enable local support for extended messages [draft] */ + int enable_hostname; /* Enable local support for hostname [draft] */ u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */ int rr_client; /* Whether neighbor is RR client of me */ int rs_client; /* Whether neighbor is RS client of me */ @@ -225,6 +226,7 @@ struct bgp_caps { u16 gr_time; /* Graceful restart time in seconds */ u8 llgr_aware; /* Long-lived GR capability, RFC draft */ + char hostname[UINT8_MAX + 1]; /* Hostname, RFC draft */ u8 any_ext_next_hop; /* Bitwise OR of per-AF ext_next_hop */ u8 any_add_path; /* Bitwise OR of per-AF add_path */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 18c3560dfc9b..f8bd4ef03b11 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -62,6 +62,7 @@ bgp_proto_start: proto_start BGP { BGP_CFG->error_delay_time_max = 300; BGP_CFG->enable_refresh = 1; BGP_CFG->enable_as4 = 1; + BGP_CFG->enable_hostname = 1; BGP_CFG->capabilities = 2; BGP_CFG->interpret_communities = 1; BGP_CFG->allow_as_sets = 1; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 78fdd1e006a3..71ab1be48b46 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -11,6 +11,7 @@ #undef LOCAL_DEBUG #include <stdlib.h> +#include <sys/utsname.h> #include "nest/bird.h" #include "nest/iface.h" @@ -221,6 +222,8 @@ bgp_prepare_capabilities(struct bgp_conn *conn) struct bgp_channel *c; struct bgp_caps *caps; struct bgp_af_caps *ac; + struct utsname uts = {}; + size_t length; if (!p->cf->capabilities) { @@ -252,6 +255,16 @@ bgp_prepare_capabilities(struct bgp_conn *conn) if (p->cf->llgr_mode) caps->llgr_aware = 1; + if (p->cf->enable_hostname) + { + uname(&uts); + if ((length = strlen(uts.nodename)) > UINT8_MAX) + length = UINT8_MAX; + memcpy(caps->hostname, uts.nodename, length); + caps->hostname[length] = 0; + } + + /* Allocate and fill per-AF fields */ WALK_LIST(c, p->p.channels) { @@ -295,6 +308,7 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf) struct bgp_af_caps *ac; byte *buf_head = buf; byte *data; + size_t length; /* Create capability list in buffer */ @@ -412,6 +426,24 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf) data[-1] = buf - data; } + if (*caps->hostname) + { + *buf++ = 73; /* Capability 73: Hostname */ + *buf++ = 0; /* Capability data length */ + data = buf; + + /* Hostname */ + length = strlen(caps->hostname); + *buf++ = length; + memcpy(buf, caps->hostname, length); + buf += length; + + /* Domain, not implemented */ + *buf++ = 0; + + data[-1] = buf - data; + } + caps->length = buf - buf_head; return buf; @@ -573,6 +605,12 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len) } break; + case 73: /* Hostname, RFC draft */ + if (cl < 2 || cl < 2 + pos[2]) + goto err; + + memcpy(caps->hostname, pos + 3, pos[2]); + /* We can safely ignore all other capabilities */ } -- 2.30.0