diff --git a/doc/bird.sgml b/doc/bird.sgml
index 8035ec18550866a69e20e02a843c800d14a5278d..096e31488d8b432651a81a8429a5c10aa958b182 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 231c10d86d7c6fb71715921ae2711452941c46b1..3417423f6091c15e283cc55fa7d7ff4f209ca660 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 4f8499bacdfa4326eed4df8018e7406b780161f3..d08c413d4ddf6ec8973e20ed0a9a49246f5c42ca 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 847c6b14bef4911b0c76159995c4e63dad6bbd2d..af31354e0f854a37b6352f8074d3e211132cebc1 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 39e7577f5a0bd4effd2db403f56aaab9697e05a3..485ddf07f559ec12d4dde5ca42646b17ee76f3a6 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 aec91ca6ba6d835e97ffac92b1cda5e8d2ff5bf8..6097bcae593f88557970f7100d5a758de0994668 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 b6b42b1eca34c8d45464c77cda932842d45c7edc..c20c7f99091ec112d0cd92cd092e560e1ba58d1f 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 f13eda7c08ad2b1f5b6847bd744d6656e478f4fb..5e71b535e20576a6e03dd6d6a8b2090f7c10e331 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 9b499020423b97a689202de7840ef428a7042ef2..da2c5492fee1578bd2e855c0ae1293d7881539b1 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 */