From f168635e4fc463ed9e7b024d20a7801180c0ce25 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Tue, 9 Jul 2024 17:03:20 +0300 Subject: [PATCH] Enable hostname capability (fqdn) Some of the open-source implementations already support this feature by default. https://datatracker.ietf.org/doc/html/draft-walton-bgp-hostname-capability-02 Tested between ExaBGP and FRR: ``` $ vtysh -c 'show bgp neighbor 127.0.0.1 json' | jq '."127.0.0.1".neighborCapabilities.hostName' { "advHostName": "donatas-laptop", "advDomainName": "n/a", "rcvHostName": "belekas", "rcvDomainName": "donatas.net" } ``` The config is: ``` neighbor 127.0.0.2 { router-id 10.10.10.10; local-address 127.0.0.1; local-as 65001; peer-as 65001; host-name belekas; domain-name donatas.net; ... } ``` Signed-off-by: Donatas Abraitis --- .../bgp/message/open/capability/capabilities.py | 2 +- .../bgp/message/open/capability/capability.py | 4 ++-- src/exabgp/bgp/message/open/capability/hostname.py | 13 +++++++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/exabgp/bgp/message/open/capability/capabilities.py b/src/exabgp/bgp/message/open/capability/capabilities.py index 7464897f1..9692a3a46 100644 --- a/src/exabgp/bgp/message/open/capability/capabilities.py +++ b/src/exabgp/bgp/message/open/capability/capabilities.py @@ -162,7 +162,7 @@ def new(self, neighbor, restarted): self._refresh(neighbor) self._operational(neighbor) self._extended_message(neighbor) - # self._hostname(neighbor) # Cumulus draft - disabling until -01 is out + self._hostname(neighbor) # https://datatracker.ietf.org/doc/html/draft-walton-bgp-hostname-capability-02 self._session(neighbor) # MUST be the last key added, really !?! dict is not ordered ! return self diff --git a/src/exabgp/bgp/message/open/capability/capability.py b/src/exabgp/bgp/message/open/capability/capability.py index 00b6dcf54..05f13767b 100644 --- a/src/exabgp/bgp/message/open/capability/capability.py +++ b/src/exabgp/bgp/message/open/capability/capability.py @@ -36,7 +36,7 @@ class _CapabilityCode(int): # 128-255 Reserved for Private Use [RFC5492] MULTISESSION_CISCO = 0x83 # What Cisco really use for Multisession (yes this is a reserved range in prod !) - HOSTNAME = 0xB8 # ExaBGP only ... + HOSTNAME = 0x49 # https://datatracker.ietf.org/doc/html/draft-walton-bgp-hostname-capability-02 OPERATIONAL = 0xB9 # ExaBGP only ... # Internal @@ -60,7 +60,7 @@ class _CapabilityCode(int): ROUTE_REFRESH_CISCO: 'cisco-route-refresh', MULTISESSION_CISCO: 'cisco-multi-sesion', AIGP: 'aigp', - HOSTNAME: 'exabgp-experimental-hostname', + HOSTNAME: 'hostname', } def __new__(cls, value): diff --git a/src/exabgp/bgp/message/open/capability/hostname.py b/src/exabgp/bgp/message/open/capability/hostname.py index c4f50d53a..d7798df4d 100644 --- a/src/exabgp/bgp/message/open/capability/hostname.py +++ b/src/exabgp/bgp/message/open/capability/hostname.py @@ -7,7 +7,7 @@ License: 3-clause BSD. (See the COPYRIGHT file) """ -# https://tools.ietf.org/html/draft-walton-bgp-hostname-capability-02 +# https://datatracker.ietf.org/doc/html/draft-walton-bgp-hostname-capability-02 from exabgp.bgp.message.open.capability.capability import Capability @@ -15,6 +15,7 @@ class HostName(Capability): ID = Capability.CODE.HOSTNAME + HOSTNAME_MAX_LEN = 64 def __init__(self, host_name, domain_name): self.host_name = host_name @@ -27,7 +28,15 @@ def json(self): return '{ "host-name": "%s", "domain-name": "%s" }' % (self.host_name, self.domain_name) def extract(self): - return [bytes([len(self.host_name)]) + self.host_name + bytes([len(self.domain_name)]) + self.domain_name] + hostname = self.host_name.encode('utf-8') + if len(hostname) > self.HOSTNAME_MAX_LEN: + hostname = hostname[:self.HOSTNAME_MAX_LEN] + + domainname = self.domain_name.encode('utf-8') + if len(domainname) > self.HOSTNAME_MAX_LEN: + domainname = domainname[:self.HOSTNAME_MAX_LEN] + + return [bytes([len(hostname)]) + hostname + bytes([len(domainname)]) + domainname] @staticmethod def unpack_capability(instance, data, capability=None): # pylint: disable=W0613