Hi all, Slightly modified the patch (names & description) in spite of the checksum verify semantics.
On Wed, Jun 26, 2024 at 9:03 AM Ville O <voj...@gmail.com> wrote: > > Hello All, > > On Tue, Jun 25, 2024 at 9:05 PM Alexander Zubkov via Bird-users > <bird-users@network.cz> wrote: > > On Tue, Jun 25, 2024 at 3:04 PM Ondrej Zajicek <santi...@crfreenet.org> > > wrote: > > > Seems to me (from cursory look at the kernel code, as it seems to be an > > > undocumented option) that the socket option UDP_NO_CHECK6_RX does not > > > disable UDP checksum verification in general, just allows to accept UDP > > > packets with zero checksum, while UDP packets with invalid non-zero > > > checksums would still be rejected. Which fits better to what we need for > > > this. > > > > I've grepped the kernel source and I agree, it seems to only accept > > zero checksums. Then maybe some phrases need to be reworded and the > > configuration option to be renamed? > > > > This is the impression I, too, got while doing research into this matter > and looking at the patches [1] that implemented this feature. > The commit message is very clear: only a checksum of 0 is > special-case accepted. > > By the way it seems the patch has been backported by RH at least > as far back as EL7 kernel version 3.10.0. > > And I have an update on my problem that started all this: > > The peer managed to update their devices to the latest Huawei OS > version and this fixed IPv6 BFD checksums. > Unfortunately the peer could not give me the old/current versions so I > cannot give information on which versions are broken and which are > fixed. I tried to get more detailed information but it just was not > possible; I can only say "latest version". > > Since the problem was fixed with the Huawei update I then regret > that I am unable to usefully test the diff. > I tested the new UDP socket option simply with scapy and maybe > something similar could work for functional testing if required. > > A big thank you to everyone! > > > Regards, > > V O > > [1]: > https://github.com/torvalds/linux/commit/1c19448c9ba6545b80ded18488a64a7f3d8e6998 >
commit 7932431fa14478648bce14249b6b110741731daf Author: Alexander Zubkov <gr...@qrator.net> Date: Sat Jun 22 19:32:48 2024 +0200 BFD: add option to allow zero checksum for rx IPv6 UDP packets Some vendors do not set the checksum for IPv6 UDP packets. For interopertability with such implementations one can set UDP_NO_CHECK6_RX socket option on Linux, in order to allow a zero checksum. diff --git a/doc/bird.sgml b/doc/bird.sgml index 8035ec18..50bfe9bc 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2499,6 +2499,7 @@ milliseconds. <code> protocol bfd [<name>] { accept [ipv4|ipv6] [direct|multihop]; + allow udp6 zero checksum rx <switch>; interface <interface pattern> { interval <time>; min rx interval <time>; @@ -2541,6 +2542,12 @@ protocol bfd [<name>] { to configure separate BFD protocol instances for IPv4 and for IPv6 sessions. + <tag><label id="bfd-allow-udp6-zero-checksum-rx">allow udp6 zero checksum rx <m/switch/</tag> + When enabled, this option configures the rx socket to allow an unset (zero) + IPv6 UDP checksum on the systems, which support such socket option + (ex. <cf>UDP_NO_CHECK6_RX</cf>). It is needed for interoperability with some + vendors that do not set the checksum. Default: disabled. + <tag><label id="bfd-strict-bind">strict bind <m/switch/</tag> Specify whether each BFD interface should use a separate listening socket bound to its local address, or just use a shared listening socket diff --git a/lib/socket.h b/lib/socket.h index 231c10d8..b3ffadad 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -131,6 +131,8 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou #define SKF_HDRINCL 0x400 /* Used internally */ #define SKF_PKTINFO 0x800 /* Used internally */ +#define SKF_UDP6_NO_CSUM_RX 0x1000 /* Allow zero checksum for incoming UDP6 */ + /* * Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must) */ diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 4f8499ba..cd78884a 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1149,7 +1149,8 @@ bfd_reconfigure(struct proto *P, struct proto_config *c) (new->accept_ipv6 != old->accept_ipv6) || (new->accept_direct != old->accept_direct) || (new->accept_multihop != old->accept_multihop) || - (new->strict_bind != old->strict_bind)) + (new->strict_bind != old->strict_bind) || + (new->udp6_no_checksum_rx != old->udp6_no_checksum_rx)) return 0; birdloop_mask_wakeups(p->loop); diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h index 847c6b14..2792ba92 100644 --- a/proto/bfd/bfd.h +++ b/proto/bfd/bfd.h @@ -48,6 +48,7 @@ struct bfd_config u8 accept_direct; u8 accept_multihop; u8 strict_bind; + u8 udp6_no_checksum_rx; }; struct bfd_iface_config diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index 39e7577f..c6d50cf8 100644 --- a/proto/bfd/config.Y +++ b/proto/bfd/config.Y @@ -24,7 +24,7 @@ CF_DECLS CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE, INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION, NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT, - STRICT, BIND) + STRICT, BIND, UDP6, CHECKSUM, ZERO) %type <iface> bfd_neigh_iface %type <a> bfd_neigh_local @@ -51,6 +51,7 @@ bfd_proto_item: | MULTIHOP bfd_multihop | NEIGHBOR bfd_neighbor | STRICT BIND bool { BFD_CFG->strict_bind = $3; } + | ALLOW UDP6 ZERO CHECKSUM RX bool { BFD_CFG->udp6_no_checksum_rx = $6; } ; bfd_proto_opts: diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index aec91ca6..0853e140 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -416,6 +416,8 @@ bfd_err_hook(sock *sk, int err) sock * bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) { + struct bfd_config *cf = (struct bfd_config *) (p->p.cf); + sock *sk = sk_new(p->tpool); sk->type = SK_UDP; sk->subtype = af; @@ -431,6 +433,8 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) sk->tos = IP_PREC_INTERNET_CONTROL; sk->priority = sk_priority_control; sk->flags = SKF_THREAD | SKF_LADDR_RX | (!multihop ? SKF_TTL_RX : 0); + if (cf->udp6_no_checksum_rx) + sk->flags |= SKF_UDP6_NO_CSUM_RX; if (sk_open(sk) < 0) goto err; @@ -447,6 +451,8 @@ err: sock * bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa) { + struct bfd_config *cf = (struct bfd_config *) (p->p.cf); + sock *sk = sk_new(p->tpool); sk->type = SK_UDP; sk->saddr = local; @@ -463,6 +469,8 @@ bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa) sk->tos = IP_PREC_INTERNET_CONTROL; sk->priority = sk_priority_control; sk->flags = SKF_THREAD | SKF_BIND | (ifa ? SKF_TTL_RX : 0); + if (cf->udp6_no_checksum_rx) + sk->flags |= SKF_UDP6_NO_CSUM_RX; if (sk_open(sk) < 0) goto err; diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 9b499020..92cb736e 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -517,6 +517,21 @@ sk_set_high_port(sock *s UNUSED) return 0; } +static inline int +sk_set_udp6_no_csum_rx(sock *s) +{ +#ifdef UDP_NO_CHECK6_RX + int y = 1; + + if (setsockopt(s->fd, SOL_UDP, UDP_NO_CHECK6_RX, &y, sizeof(y)) < 0) + ERR("UDP_NO_CHECK6_RX"); + + return 0; +#else + ERR("UDP_NO_CHECK6_RX"); +#endif +} + static inline byte * sk_skip_ip_header(byte *pkt, int *len) { @@ -1475,6 +1490,10 @@ sk_open(sock *s) if (sk_set_freebind(s) < 0) log(L_WARN "Socket error: %s%#m", s->err); + if (s->flags & SKF_UDP6_NO_CSUM_RX && s->af == AF_INET6 && s->type == SK_UDP) + if (sk_set_udp6_no_csum_rx(s) < 0) + log(L_WARN "Socket error: %s%#m", s->err); + sockaddr_fill(&sa, s->af, bind_addr, s->iface, bind_port); if (bind(fd, &sa.sa, SA_LEN(sa)) < 0) ERR2("bind");