0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 01:54:08 +00:00

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.
This commit is contained in:
Alexander Zubkov 2024-06-26 16:29:57 +02:00 committed by Ondrej Zajicek
parent 00b139bd25
commit 8a40bccffe
9 changed files with 45 additions and 2 deletions

View File

@ -2499,6 +2499,7 @@ milliseconds.
<code> <code>
protocol bfd [&lt;name&gt;] { protocol bfd [&lt;name&gt;] {
accept [ipv4|ipv6] [direct|multihop]; accept [ipv4|ipv6] [direct|multihop];
zero udp6 checksum rx &lt;switch&gt;;
interface &lt;interface pattern&gt; { interface &lt;interface pattern&gt; {
interval &lt;time&gt;; interval &lt;time&gt;;
min rx 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 in cases like running multiple BIRD instances on a machine, each
handling a different set of interfaces. Default: disabled. 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> <tag><label id="bfd-iface">interface <m/pattern/ [, <m/.../] { <m/options/ }</tag>
Interface definitions allow to specify options for sessions associated Interface definitions allow to specify options for sessions associated
with such interfaces and also may contain interface specific options. with such interfaces and also may contain interface specific options.

View File

@ -131,6 +131,8 @@ extern int sk_priority_control; /* Suggested priority for control traffic, shou
#define SKF_HDRINCL 0x400 /* Used internally */ #define SKF_HDRINCL 0x400 /* Used internally */
#define SKF_PKTINFO 0x800 /* 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) * Socket types SA SP DA DP IF TTL SendTo (?=may, -=must not, *=must)
*/ */

View File

@ -1149,7 +1149,8 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
(new->accept_ipv6 != old->accept_ipv6) || (new->accept_ipv6 != old->accept_ipv6) ||
(new->accept_direct != old->accept_direct) || (new->accept_direct != old->accept_direct) ||
(new->accept_multihop != old->accept_multihop) || (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; return 0;
birdloop_mask_wakeups(p->loop); birdloop_mask_wakeups(p->loop);

View File

@ -48,6 +48,7 @@ struct bfd_config
u8 accept_direct; u8 accept_direct;
u8 accept_multihop; u8 accept_multihop;
u8 strict_bind; u8 strict_bind;
u8 zero_udp6_checksum_rx;
}; };
struct bfd_iface_config struct bfd_iface_config

View File

@ -24,7 +24,7 @@ CF_DECLS
CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE, CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE,
INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION, INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION,
NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT, NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT,
STRICT, BIND) STRICT, BIND, ZERO, UDP6, CHECKSUM, RX)
%type <iface> bfd_neigh_iface %type <iface> bfd_neigh_iface
%type <a> bfd_neigh_local %type <a> bfd_neigh_local
@ -51,6 +51,7 @@ bfd_proto_item:
| MULTIHOP bfd_multihop | MULTIHOP bfd_multihop
| NEIGHBOR bfd_neighbor | NEIGHBOR bfd_neighbor
| STRICT BIND bool { BFD_CFG->strict_bind = $3; } | STRICT BIND bool { BFD_CFG->strict_bind = $3; }
| ZERO UDP6 CHECKSUM RX bool { BFD_CFG->zero_udp6_checksum_rx = $5; }
; ;
bfd_proto_opts: bfd_proto_opts:

View File

@ -416,6 +416,8 @@ bfd_err_hook(sock *sk, int err)
sock * sock *
bfd_open_rx_sk(struct bfd_proto *p, int multihop, int af) 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); sock *sk = sk_new(p->tpool);
sk->type = SK_UDP; sk->type = SK_UDP;
sk->subtype = af; 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->priority = sk_priority_control;
sk->flags = SKF_THREAD | SKF_LADDR_RX | (!multihop ? SKF_TTL_RX : 0); 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) if (sk_open(sk) < 0)
goto err; goto err;
@ -447,6 +452,8 @@ err:
sock * sock *
bfd_open_rx_sk_bound(struct bfd_proto *p, ip_addr local, struct iface *ifa) 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); sock *sk = sk_new(p->tpool);
sk->type = SK_UDP; sk->type = SK_UDP;
sk->saddr = local; 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->priority = sk_priority_control;
sk->flags = SKF_THREAD | SKF_BIND | (ifa ? SKF_TTL_RX : 0); 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) if (sk_open(sk) < 0)
goto err; goto err;

View File

@ -309,3 +309,9 @@ sk_set_freebind(sock *s)
{ {
ERR_MSG("Freebind is not supported"); 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");
}

View File

@ -285,3 +285,12 @@ sk_set_freebind(sock *s)
return 0; 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");
}

View File

@ -1046,6 +1046,10 @@ sk_setup(sock *s)
if (s->tos >= 0) if (s->tos >= 0)
if (sk_set_tos6(s, s->tos) < 0) if (sk_set_tos6(s, s->tos) < 0)
return -1; 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 */ /* Must be after sk_set_tos4() as setting ToS on Linux also mangles priority */