[PATCH v2] BGP: Add support for BGP hostname capability

Vincent Bernat vincent at bernat.ch
Fri Feb 5 15:12:01 CET 2021


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.

It is disabled by default. The hostname is retrieved from uname(2) and
can be overriden with "hostname". The domain name is never set nor
displayed. I don't think the domain name is useful.

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 <vincent at bernat.ch>
---
 conf/conf.c         | 14 ++++++++++++++
 conf/conf.h         |  1 +
 doc/bird.sgml       |  6 ++++++
 nest/cmds.c         |  1 +
 nest/config.Y       |  6 +++++-
 proto/bgp/bgp.c     |  3 +++
 proto/bgp/bgp.h     |  2 ++
 proto/bgp/config.Y  |  2 ++
 proto/bgp/packets.c | 36 ++++++++++++++++++++++++++++++++++++
 9 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/conf/conf.c b/conf/conf.c
index 6f64b5416c59..1b699c97361e 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -42,6 +42,7 @@
 
 #include <setjmp.h>
 #include <stdarg.h>
+#include <sys/utsname.h>
 
 #undef LOCAL_DEBUG
 
@@ -217,6 +218,19 @@ config_del_obstacle(struct config *c)
 static int
 global_commit(struct config *new, struct config *old)
 {
+  if (!new->hostname)
+    {
+      struct utsname uts = {};
+      if (uname(&uts) == -1)
+        log(L_WARN "Cannot determine hostname");
+      else
+      {
+        char *hostname;
+        hostname = lp_strdup(new->mem, uts.nodename);
+        new->hostname = hostname;
+      }
+    }
+
   if (!old)
     return 0;
 
diff --git a/conf/conf.h b/conf/conf.h
index 3e47c9185469..860d267aa7b9 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -40,6 +40,7 @@ struct config {
   struct timeformat tf_log;		/* Time format for the logfile */
   struct timeformat tf_base;		/* Time format for other purposes */
   u32 gr_wait;				/* Graceful restart wait timeout (sec) */
+  const char *hostname;			/* Hostname */
 
   int cli_debug;			/* Tracing of CLI connections and commands */
   int latency_debug;			/* I/O loop tracks duration of each event */
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 28b0e400b464..592a76a294ea 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -585,6 +585,9 @@ include "tablename.conf";;
 	See <ref id="proto-iface" name="interface"> section for detailed
 	description of interface patterns with extended clauses.
 
+	<tag><label id="opt-hostname">hostname "<m/name/</tag>
+	Set hostname. Default: node name as returned by 'uname -n'.
+
 	<tag><label id="opt-graceful-restart">graceful restart wait <m/number/</tag>
 	During graceful restart recovery, BIRD waits for convergence of routing
 	protocols. This option allows to specify a timeout for the recovery to
@@ -2536,6 +2539,9 @@ using the following configuration parameters:
 	This option is relevant to IPv4 mode with enabled capability
 	advertisement only. Default: on.
 
+	<tag><label id="bgp-advertise-hostname">advertise hostname <m/switch/</tag>
+	Advertise hostname capability along with the hostname. Default: off.
+
 	<tag><label id="bgp-disable-after-error">disable after error <m/switch/</tag>
 	When an error is encountered (either locally or by the other side),
 	disable the instance automatically and wait for an administrator to fix
diff --git a/nest/cmds.c b/nest/cmds.c
index da4015cfba0d..18f39eb56c10 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -27,6 +27,7 @@ cmd_show_status(void)
   cli_msg(-1000, "BIRD " BIRD_VERSION);
   tm_format_time(tim, &config->tf_base, current_time());
   cli_msg(-1011, "Router ID is %R", config->router_id);
+  cli_msg(-1011, "Hostname is %s", config->hostname);
   cli_msg(-1011, "Current server time is %s", tim);
   tm_format_time(tim, &config->tf_base, boot_time);
   cli_msg(-1011, "Last reboot on %s", tim);
diff --git a/nest/config.Y b/nest/config.Y
index 0bb8ca51dba0..39bf61490001 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -87,7 +87,7 @@ proto_postconfig(void)
 
 CF_DECLS
 
-CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
+CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
 CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
 CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
 CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
@@ -151,6 +151,10 @@ idval:
    }
  ;
 
+conf: hostname_override ;
+
+hostname_override: HOSTNAME text ';' { new_config->hostname = $2; } ;
+
 conf: gr_opts ;
 
 gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 302d026c0103..a23871f42b9d 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..d6cbaa5b53b8 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;			/* 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..2dfbdca9bc92 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 = 0;
      BGP_CFG->capabilities = 2;
      BGP_CFG->interpret_communities = 1;
      BGP_CFG->allow_as_sets = 1;
@@ -173,6 +174,7 @@ bgp_proto:
  | bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
  | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
  | bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
+ | bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; }
  | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
  | bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
  | bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 78fdd1e006a3..0fb24c617e02 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -252,6 +252,13 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
   if (p->cf->llgr_mode)
     caps->llgr_aware = 1;
 
+  if (p->cf->enable_hostname)
+  {
+    size_t length = strlen(p->cf->c.global->hostname);
+    caps->hostname = mb_allocz(p->p.pool, length+1);
+    memcpy(caps->hostname, p->cf->c.global->hostname, length);
+  }
+
   /* Allocate and fill per-AF fields */
   WALK_LIST(c, p->p.channels)
   {
@@ -295,6 +302,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 +420,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 +599,16 @@ 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;
+
+      caps->hostname = mb_allocz(p->p.pool, pos[2]+1);
+      memcpy(caps->hostname, pos + 3, pos[2]);
+      for (i = 0; i < pos[2]; i++)
+        if (caps->hostname[i] < ' ')
+          caps->hostname[i] = ' ';
+
       /* We can safely ignore all other capabilities */
     }
 
-- 
2.30.0



More information about the Bird-users mailing list