diff options
author | Alexander Zubkov <green@qrator.net> | 2024-06-26 16:29:57 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2024-06-26 16:29:57 +0200 |
commit | 8a40bccffe9e28e211fe996845658f87f5cc60e9 (patch) | |
tree | bd01e74c27ba6de8cb571475ffd7534d8d8e97e1 | |
parent | 00b139bd25c77b401d2065283cb970d9d8c1aa02 (diff) |
BFD: Add option to accept zero checksum for IPv6 UDP packets
Some vendors do not fill the checksum for IPv6 UDP packets.
For interoperability with such implementations one can set
UDP_NO_CHECK6_RX socket option on Linux.
Thanks to Ville O for the suggestion.
Minor changes by committer.
-rw-r--r-- | doc/bird.sgml | 9 | ||||
-rw-r--r-- | lib/socket.h | 2 | ||||
-rw-r--r-- | proto/bfd/bfd.c | 3 | ||||
-rw-r--r-- | proto/bfd/bfd.h | 1 | ||||
-rw-r--r-- | proto/bfd/config.Y | 3 | ||||
-rw-r--r-- | proto/bfd/packets.c | 10 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 6 | ||||
-rw-r--r-- | sysdep/linux/sysio.h | 9 | ||||
-rw-r--r-- | sysdep/unix/io.c | 4 |
9 files changed, 45 insertions, 2 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml index 8035ec18..096e3148 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -2499,6 +2499,7 @@ milliseconds. <code> protocol bfd [<name>] { accept [ipv4|ipv6] [direct|multihop]; + zero udp6 checksum rx <switch>; interface <interface pattern> { interval <time>; min rx interval <time>; @@ -2548,6 +2549,14 @@ protocol bfd [<name>] { in cases like running multiple BIRD instances on a machine, each handling a different set of interfaces. Default: disabled. + <tag><label id="bfd-zero-udp6-checksum-rx">zero udp6 checksum rx <m/switch/</tag> + UDP checksum computation is optional in IPv4 while it is mandatory in + IPv6. Some BFD implementations send UDP datagrams with zero (blank) + checksum even in IPv6 case. This option configures BFD listening sockets + to accept such datagrams. It is available only on platforms that support + the relevant socket option (e.g. <cf/UDP_NO_CHECK6_RX/ on Linux). + Default: disabled. + <tag><label id="bfd-iface">interface <m/pattern/ [, <m/.../] { <m/options/ }</tag> Interface definitions allow to specify options for sessions associated with such interfaces and also may contain interface specific options. diff --git a/lib/socket.h b/lib/socket.h index 231c10d8..3417423f 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 /* Accept zero checksums for received UDPv6 packets */ + /* * 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..d08c413d 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->zero_udp6_checksum_rx != old->zero_udp6_checksum_rx)) return 0; birdloop_mask_wakeups(p->loop); diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h index 847c6b14..af31354e 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 zero_udp6_checksum_rx; }; struct bfd_iface_config diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index 39e7577f..485ddf07 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, ZERO, UDP6, CHECKSUM, RX) %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; } + | ZERO UDP6 CHECKSUM RX bool { BFD_CFG->zero_udp6_checksum_rx = $5; } ; bfd_proto_opts: diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index aec91ca6..6097bcae 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; @@ -432,6 +434,9 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) sk->priority = sk_priority_control; sk->flags = SKF_THREAD | SKF_LADDR_RX | (!multihop ? SKF_TTL_RX : 0); + if (cf->zero_udp6_checksum_rx) + sk->flags |= SKF_UDP6_NO_CSUM_RX; + if (sk_open(sk) < 0) goto err; @@ -447,6 +452,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; @@ -464,6 +471,9 @@ bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa) sk->priority = sk_priority_control; sk->flags = SKF_THREAD | SKF_BIND | (ifa ? SKF_TTL_RX : 0); + if (cf->zero_udp6_checksum_rx) + sk->flags |= SKF_UDP6_NO_CSUM_RX; + if (sk_open(sk) < 0) goto err; diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index b6b42b1e..c20c7f99 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -309,3 +309,9 @@ sk_set_freebind(sock *s) { ERR_MSG("Freebind is not supported"); } + +static inline int +sk_set_udp6_no_csum_rx(sock *s) +{ + ERR_MSG("UDPv6 zero checksum is not supported"); +} diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index f13eda7c..5e71b535 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -285,3 +285,12 @@ sk_set_freebind(sock *s) return 0; } + +static inline int +sk_set_udp6_no_csum_rx(sock *s) +{ + int y = 1; + + if (setsockopt(s->fd, SOL_UDP, UDP_NO_CHECK6_RX, &y, sizeof(y)) < 0) + ERR("UDP_NO_CHECK6_RX"); +} diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 9b499020..da2c5492 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -1046,6 +1046,10 @@ sk_setup(sock *s) if (s->tos >= 0) if (sk_set_tos6(s, s->tos) < 0) return -1; + + if ((s->flags & SKF_UDP6_NO_CSUM_RX) && (s->type == SK_UDP)) + if (sk_set_udp6_no_csum_rx(s) < 0) + return -1; } /* Must be after sk_set_tos4() as setting ToS on Linux also mangles priority */ |