Description
bfdd's distributed-BFD client mode over a unix socket (--dplaneaddr unixc:<path>) never establishes a connection. Every connect attempt fails with EINVAL and retries every 3 seconds. The TCP transports (ipv4c:/ipv6c:) work fine.
Root cause: bfd_dplane_client_init() in bfdd/dplane.c discards the caller's salen and stores the size of the address union instead:
if (salen <= sizeof(bdc->addr)) {
memcpy(&bdc->addr, sa, salen);
bdc->addrlen = sizeof(bdc->addr); /* should be salen */
bdc->addr is a union of sockaddr / sockaddr_in / sockaddr_in6 / sockaddr_un. sizeof(struct sockaddr_un) is 110, but the union is padded to 112 by sockaddr_in6 alignment. bfd_dplane_client_connect() then calls connect() with addrlen=112, and the kernel's AF_UNIX address validation (unix_validate_addr() in net/unix/af_unix.c) rejects any addrlen greater than sizeof(struct sockaddr_un) with -EINVAL. Inet sockets tolerate oversized addrlen, which is why only the unix transport is affected.
git log -S addrlen -- bfdd/dplane.c shows this logic is unchanged since client mode was introduced (6655b43, "bfdd: support connecting to BFD data plane"), and the code is identical on current master — so unixc: appears to have never worked on Linux.
The fix is one line (verified locally, see Additional context):
memcpy(&bdc->addr, sa, salen);
bdc->addrlen = salen;
with the truncation branch keeping sizeof(bdc->addr) as today. Happy to send a PR.
Version
w453y@bfd-dut:~/xdp-bfd$ sudo vtysh -c "show version" FRRouting 10.5.1 (bfd-dut) on Linux(7.0.0-27-generic). Copyright 1996-2005 Kunihiro Ishiguro, et al. configured with:
'--build=x86_64-linux-gnu' '--prefix=/usr' '--includedir=${prefix}/include' '--mandir=${prefix}/share/man' '--infodir=${prefix}/share/info' '--sysconfdir=/etc' '--localstatedir=/var' '--disable-option-checking' '--disable-silent-rules' '--libdir=${prefix}/lib/x86_64-linux-gnu' '--runstatedir=/run' '--disable-maintainer-mode' '--sbindir=/usr/lib/frr' '--with-vtysh-pager=/usr/bin/pager' '--libdir=/usr/lib/x86_64-linux-gnu/frr' '--with-moduledir=/usr/lib/x86_64-linux-gnu/frr/modules' '--disable-dependency-tracking' '--enable-rpki' '--enable-scripting' '--enable-pim6d' '--with-libpam' '--enable-doc' '--enable-doc-html' '--enable-snmp' '--enable-fpm' '--disable-protobuf' '--disable-zeromq' '--enable-ospfapi' '--enable-bgp-vnc' '--enable-multipath=256' '--enable-user=frr' '--enable-group=frr' '--enable-vty-group=frrvty' '--enable-configfile-mask=0640' '--enable-logfile-mask=0640' 'build_alias=x86_64-linux-gnu' 'LIBS= -latomic' 'PYTHON=python3'
w453y@bfd-dut:~/xdp-bfd$
Distro package: Ubuntu 26.04, frr 10.5.1-1ubuntu4.1 (Ubuntu's configure flags). Kernel 7.0.0-27-generic, x86_64.
Not yet tested against a build of current master, but the relevant code in bfdd/dplane.c is byte-identical on master (checked at commit 4c4f48295a), so the behavior is expected to be identical.
How to reproduce
Single host, no BFD peers needed — the failure is the local dataplane socket connection itself.
-
Start any unix-socket listener:
socat UNIX-LISTEN:/tmp/frr-repro.sock,fork,mode=777 -
-
Start bfdd in dataplane client mode, e.g. in /etc/frr/daemons:
bfdd_options=" --daemon -A 127.0.0.1 --dplaneaddr unixc:/tmp/frr-repro.sock"
then: systemctl restart frr
-
Observe: journalctl -u frr | grep dplane, and/or strace -f -e trace=connect -p $(pidof bfdd)
Expected behavior
bfdd connects to the unix-socket dataplane listener, the same way it successfully connects with the TCP transport (ipv4c:).
Actual behavior
The connection never establishes; bfdd retries every 3 seconds:
bfdd[13438]: [K880F-QRW5M] bfd_dplane_client_connect: data plane connection failed: Invalid argument
strace shows the oversized address length being passed to connect(2):
connect(16, {sa_family=AF_UNIX, sun_path="/tmp/frr-repro.sock"}, 112) = -1 EINVAL (Invalid argument)
Size check compiled on the same system (x86_64, glibc):
sizeof(sockaddr_un) = 110
sizeof(sockaddr_in6) = 28
sizeof(union addr) = 112
Additional context
Fix verified locally: rebuilt bfdd from the 10.5.1 source with only the one-line change (bdc->addrlen = salen; in the non-truncating branch of bfd_dplane_client_init) and it successfully connects to the same unix-socket listener that stock bfdd fails against with EINVAL.
Found while building an external BFD dataplane against the bfddp protocol (https://github.com/w453y/xdp-bfd). The ipv4c: transport works end-to-end with unmodified bfdd, so this is purely the unix client path.
Checklist
Description
bfdd's distributed-BFD client mode over a unix socket (
--dplaneaddr unixc:<path>) never establishes a connection. Every connect attempt fails with EINVAL and retries every 3 seconds. The TCP transports (ipv4c:/ipv6c:) work fine.Root cause:
bfd_dplane_client_init()in bfdd/dplane.c discards the caller'ssalenand stores the size of the address union instead:bdc->addris a union of sockaddr / sockaddr_in / sockaddr_in6 / sockaddr_un. sizeof(struct sockaddr_un) is 110, but the union is padded to 112 by sockaddr_in6 alignment.bfd_dplane_client_connect()then calls connect() with addrlen=112, and the kernel's AF_UNIX address validation (unix_validate_addr() in net/unix/af_unix.c) rejects any addrlen greater than sizeof(struct sockaddr_un) with -EINVAL. Inet sockets tolerate oversized addrlen, which is why only the unix transport is affected.git log -S addrlen -- bfdd/dplane.cshows this logic is unchanged since client mode was introduced (6655b43, "bfdd: support connecting to BFD data plane"), and the code is identical on current master — so unixc: appears to have never worked on Linux.The fix is one line (verified locally, see Additional context):
with the truncation branch keeping sizeof(bdc->addr) as today. Happy to send a PR.
Version
How to reproduce
Single host, no BFD peers needed — the failure is the local dataplane socket connection itself.
Start any unix-socket listener:
Start bfdd in dataplane client mode, e.g. in /etc/frr/daemons:
then: systemctl restart frr
Observe: journalctl -u frr | grep dplane, and/or strace -f -e trace=connect -p $(pidof bfdd)
Expected behavior
bfdd connects to the unix-socket dataplane listener, the same way it successfully connects with the TCP transport (ipv4c:).
Actual behavior
The connection never establishes; bfdd retries every 3 seconds:
strace shows the oversized address length being passed to connect(2):
Size check compiled on the same system (x86_64, glibc):
Additional context
Fix verified locally: rebuilt bfdd from the 10.5.1 source with only the one-line change (bdc->addrlen = salen; in the non-truncating branch of bfd_dplane_client_init) and it successfully connects to the same unix-socket listener that stock bfdd fails against with EINVAL.
Found while building an external BFD dataplane against the bfddp protocol (https://github.com/w453y/xdp-bfd). The ipv4c: transport works end-to-end with unmodified bfdd, so this is purely the unix client path.
Checklist