summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Zubkov <green@qrator.net>2024-06-26 16:29:57 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2024-06-26 16:29:57 +0200
commit8a40bccffe9e28e211fe996845658f87f5cc60e9 (patch)
treebd01e74c27ba6de8cb571475ffd7534d8d8e97e1
parent00b139bd25c77b401d2065283cb970d9d8c1aa02 (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.sgml9
-rw-r--r--lib/socket.h2
-rw-r--r--proto/bfd/bfd.c3
-rw-r--r--proto/bfd/bfd.h1
-rw-r--r--proto/bfd/config.Y3
-rw-r--r--proto/bfd/packets.c10
-rw-r--r--sysdep/bsd/sysio.h6
-rw-r--r--sysdep/linux/sysio.h9
-rw-r--r--sysdep/unix/io.c4
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 [&lt;name&gt;] {
accept [ipv4|ipv6] [direct|multihop];
+ zero udp6 checksum rx &lt;switch&gt;;
interface &lt;interface pattern&gt; {
interval &lt;time&gt;;
min rx interval &lt;time&gt;;
@@ -2548,6 +2549,14 @@ protocol bfd [&lt;name&gt;] {
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 */