mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-17 08:38:42 +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:
parent
00b139bd25
commit
8a40bccffe
@ -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.
|
||||
|
@ -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)
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user