Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Jan 2025 22:08:14 GMT
From:      Olivier Cochard <olivier@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   git: 4516e09a236b - main - net/bird3: Add new branch 3.x (multithreaded)
Message-ID:  <202501092208.509M8E3C053936@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by olivier:

URL: https://cgit.FreeBSD.org/ports/commit/?id=4516e09a236bb31d6e852eadfb05f9576e4db7da

commit 4516e09a236bb31d6e852eadfb05f9576e4db7da
Author:     Olivier Cochard <olivier@FreeBSD.org>
AuthorDate: 2025-01-09 21:58:36 +0000
Commit:     Olivier Cochard <olivier@FreeBSD.org>
CommitDate: 2025-01-09 22:07:38 +0000

    net/bird3: Add new branch 3.x (multithreaded)
    
    Warning: Consider version 3.0.0 to be unstable.
    
    PR:             283403
    Sponsored by:   Netflix
---
 net/Makefile                                       |   1 +
 net/bird2/Makefile                                 |   3 +-
 net/bird3/Makefile                                 |  62 ++++
 net/bird3/distinfo                                 |   3 +
 net/bird3/files/bird.in                            |  30 ++
 .../patch-00-kernel-Fix-crash-for-merge-paths      |  38 ++
 net/bird3/files/patch-01-Table-not-feeding-twice   |  39 ++
 .../files/patch-02-kernel-trace-the-final-result   |  53 +++
 net/bird3/files/patch-03-BGP-fix-locking-order     | 176 +++++++++
 .../files/patch-04-BFD-Fix-session-locking-order   | 400 +++++++++++++++++++++
 .../files/patch-05-mainloop-dropped-old-socket     |  86 +++++
 net/bird3/files/patch-06-cli-allocate-tx-buffers   | 134 +++++++
 net/bird3/files/patch-07-cli-flushing-tmp-linpool  |  29 ++
 net/bird3/files/patch-08-kernel-feed-only-once     | 274 ++++++++++++++
 net/bird3/files/patch-09-graceful-recovery         | 311 ++++++++++++++++
 net/bird3/files/patch-10-stonehenge                | 116 ++++++
 net/bird3/files/patch-11-route-attribute-storage   |  80 +++++
 net/bird3/files/patch-12-BGP-tx-bucket-storage     |  84 +++++
 .../files/patch-13-allocate-normalization-buckets  | 100 ++++++
 net/bird3/files/patch-14-BGP-fix-dislpay-name      |  25 ++
 .../patch-15-BGP-fixed-deterministic-med-crashes   |  65 ++++
 .../files/patch-16-Table-old-best-route-refeed-fix |  87 +++++
 net/bird3/files/patch-Makefile.in                  |  11 +
 net/bird3/files/pkg-message.in                     |  11 +
 net/bird3/pkg-descr                                |  14 +
 net/bird3/pkg-plist                                |   4 +
 26 files changed, 2234 insertions(+), 2 deletions(-)

diff --git a/net/Makefile b/net/Makefile
index 151a98fa8881..9093da9bdb0b 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -57,6 +57,7 @@
     SUBDIR += bindtest
     SUBDIR += binkd
     SUBDIR += bird2
+    SUBDIR += bird3
     SUBDIR += bittwist
     SUBDIR += bmon
     SUBDIR += boinc-client
diff --git a/net/bird2/Makefile b/net/bird2/Makefile
index 7a6d87747d6f..3a5dc86df54a 100644
--- a/net/bird2/Makefile
+++ b/net/bird2/Makefile
@@ -15,8 +15,7 @@ rtsock_PKGNAMESUFFIX=	2-rtsock
 
 USES=		bison cpe gmake ncurses readline
 
-CONFLICTS=	bird
-CONFLICTS+=	bird6
+CONFLICTS=	bird3
 
 CPE_VENDOR=	nic
 
diff --git a/net/bird3/Makefile b/net/bird3/Makefile
new file mode 100644
index 000000000000..8c27bcafdc41
--- /dev/null
+++ b/net/bird3/Makefile
@@ -0,0 +1,62 @@
+PORTNAME=	bird
+DISTVERSION=	3.0.0
+CATEGORIES=	net
+MASTER_SITES=	https://bird.network.cz/download/
+PKGNAMESUFFIX=	3
+
+MAINTAINER=	olivier@FreeBSD.org
+COMMENT=	Dynamic multithreaded IP routing daemon
+WWW=		https://bird.network.cz/
+
+LICENSE=	GPLv2
+
+USES=		bison cpe gmake ncurses readline
+
+CONFLICTS=	bird2
+
+CPE_VENDOR=	nic
+
+USE_CSTD=	gnu99
+GNU_CONFIGURE=	yes
+CONFIGURE_ARGS=	--localstatedir=/var
+USE_RC_SUBR=	bird
+SUB_FILES=	pkg-message
+
+GROUPS=		birdvty
+
+MAKE_JOBS_UNSAFE=	yes
+
+OPTIONS_MULTI=	RP
+RP_DESC=	Routing Protocols
+OPTIONS_MULTI_RP=	BFD BABEL BMP BGP MRT OSPF PIPE RADV RIP RPKI STATIC
+OPTIONS_DEFAULT=	BFD BABEL BGP MRT OSPF PIPE RADV RIP RPKI STATIC
+
+BFD_DESC=	Bidirectional Forwarding Detection
+BABEL_DESC=	Babel routing protocol
+BGP_DESC=	Border Gateway Protocol
+BMP_DESC=	BGP Monitoring Protocol
+MRT_DESC=	Dumping Routing Information in MRT Format
+OSPF_DESC=	Open Short Path First
+PIPE_DESC=	PIPE routing
+RADV_DESC=	Router Advertisement
+RIP_DESC=	Routing Information Protocol
+RPKI_DESC=	Resource Public Key Infrastructure
+STATIC_DESC=	Static routing
+
+BFD_VARS=	rt_prot+=bfd
+BABEL_VARS=	rt_prot+=babel
+BGP_VARS=	rt_prot+=bgp
+BMP_VARS=	rt_prot+=bmp
+MRT_VARS=	rt_prot+=mrt
+OSPF_VARS=	rt_prot+=ospf
+PIPE_VARS=	rt_prot+=pipe
+RADV_VARS=	rt_prot+=radv
+RIP_VARS=	rt_prot+=rip
+RPKI_VARS=	rt_prot+=rpki
+STATIC_VARS=	rt_prot+=static
+
+CONFIGURE_ARGS+=--with-protocols="${RT_PROT}"
+CONFIGURE_ARGS+=--with-sysconfig=bsd-netlink
+RPKI_LIB_DEPENDS=	libssh.so:security/libssh
+
+.include <bsd.port.mk>
diff --git a/net/bird3/distinfo b/net/bird3/distinfo
new file mode 100644
index 000000000000..66fda3f7d35c
--- /dev/null
+++ b/net/bird3/distinfo
@@ -0,0 +1,3 @@
+TIMESTAMP = 1734554961
+SHA256 (bird-3.0.0.tar.gz) = 8130440a2e273ba6456df2fb3acb43da7cb4d566f94a294a3a52a1b118f2512a
+SIZE (bird-3.0.0.tar.gz) = 2641569
diff --git a/net/bird3/files/bird.in b/net/bird3/files/bird.in
new file mode 100644
index 000000000000..de800bd69b81
--- /dev/null
+++ b/net/bird3/files/bird.in
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# PROVIDE: bird dynamicrouting
+# REQUIRE: LOGIN
+# KEYWORD: shutdown
+#
+# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
+# to enable this service:
+#
+# bird_enable (bool):   Set to NO by default.
+#               Set it to YES to enable bird.
+# bird_config (path):   Set to %%PREFIX%%/etc/bird.conf
+#               by default.
+#
+
+. /etc/rc.subr
+
+name="bird"
+rcvar=bird_enable
+
+load_rc_config $name
+
+: ${bird_enable="NO"}
+: ${bird_config="%%PREFIX%%/etc/bird.conf"}
+: ${bird_group="birdvty"}
+
+command=%%PREFIX%%/sbin/${name}
+command_args="-c $bird_config -g $bird_group"
+
+run_rc_command "$1"
diff --git a/net/bird3/files/patch-00-kernel-Fix-crash-for-merge-paths b/net/bird3/files/patch-00-kernel-Fix-crash-for-merge-paths
new file mode 100644
index 000000000000..d008d4cf070c
--- /dev/null
+++ b/net/bird3/files/patch-00-kernel-Fix-crash-for-merge-paths
@@ -0,0 +1,38 @@
+From b6caccfd45fb639b6dd3a8d140d3c5ba4cc79311 Mon Sep 17 00:00:00 2001
+From: Maria Matejka <mq@ucw.cz>
+Date: Thu, 19 Dec 2024 11:00:15 +0100
+Subject: [PATCH] Kernel: Fix crash for merge paths on if no route is in BIRD
+
+There was a missing check for a NULL return value.
+Also fixed an indenting error.
+
+Thanks to Radu Anghel for reporting it:
+https://bird.network.cz/pipermail/bird-users/2024-December/017977.html
+---
+ nest/rt-table.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/nest/rt-table.c b/nest/rt-table.c
+index fd8bb50dd..05191d743 100644
+--- nest/rt-table.c
++++ nest/rt-table.c
+@@ -5265,14 +5265,14 @@ krt_export_net(struct channel *c, const net_addr *a, linpool *lp)
+   if (c->ra_mode == RA_MERGED)
+   {
+     struct rt_export_feed *feed = rt_net_feed(c->table, a, NULL);
+-    if (!feed->count_routes)
++    if (!feed || !feed->count_routes)
+       return NULL;
+ 
+     if (!bmap_test(&c->export_accepted_map, feed->block[0].id))
+       return NULL;
+ 
+     return rt_export_merged(c, feed, lp, 1);
+-    }
++  }
+ 
+   static _Thread_local rte best;
+   best = rt_net_best(c->table, a);
+-- 
+GitLab
+
diff --git a/net/bird3/files/patch-01-Table-not-feeding-twice b/net/bird3/files/patch-01-Table-not-feeding-twice
new file mode 100644
index 000000000000..4fb40a644fb2
--- /dev/null
+++ b/net/bird3/files/patch-01-Table-not-feeding-twice
@@ -0,0 +1,39 @@
+From 0a2f92ad205d96d0be0945ecf2bb740b68d5a3c1 Mon Sep 17 00:00:00 2001
+From: Maria Matejka <mq@ucw.cz>
+Date: Thu, 19 Dec 2024 11:54:05 +0100
+Subject: [PATCH] Table: not feeding twice, once is enough
+
+If there is no feed pending, the requested one should be
+activated immediately, otherwise it is activated only after
+the full run, effectively running first a full feed and
+then the requested one.
+---
+ nest/rt-export.c | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/nest/rt-export.c b/nest/rt-export.c
+index 7368447de..7d51e54cf 100644
+--- nest/rt-export.c
++++ nest/rt-export.c
+@@ -357,8 +357,16 @@ rt_export_refeed_feeder(struct rt_export_feeder *f, struct rt_feeding_request *r
+   if (!rfr)
+     return;
+ 
+-  rfr->next = f->feed_pending;
+-  f->feed_pending = rfr;
++  if (f->feeding)
++  {
++    rfr->next = f->feed_pending;
++    f->feed_pending = rfr;
++  }
++  else
++  {
++    rfr->next = NULL;
++    f->feeding = rfr;
++  }
+ }
+ 
+ void rt_export_refeed_request(struct rt_export_request *rer, struct rt_feeding_request *rfr)
+-- 
+GitLab
+
diff --git a/net/bird3/files/patch-02-kernel-trace-the-final-result b/net/bird3/files/patch-02-kernel-trace-the-final-result
new file mode 100644
index 000000000000..a3c97320f30e
--- /dev/null
+++ b/net/bird3/files/patch-02-kernel-trace-the-final-result
@@ -0,0 +1,53 @@
+From ab74652f96c301dd2d2d2a831dd1a159ae1d5e02 Mon Sep 17 00:00:00 2001
+From: Maria Matejka <mq@ucw.cz>
+Date: Thu, 19 Dec 2024 12:28:27 +0100
+Subject: [PATCH] Kernel: when channel traces, we have to trace the final
+ result
+
+Otherwise it looks like we are sending too much traffic to netlink
+every other while, which is not true. Now we can disambiguate between
+in-kernel updates and ignored routes.
+---
+ sysdep/unix/krt.c | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
+index 2770b8be2..34882b88f 100644
+--- sysdep/unix/krt.c
++++ sysdep/unix/krt.c
+@@ -672,7 +672,7 @@ krt_preexport(struct channel *C, rte *e)
+ }
+ 
+ static void
+-krt_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net,
++krt_rt_notify(struct proto *P, struct channel *ch, const net_addr *net,
+ 	      rte *new, const rte *old)
+ {
+   struct krt_proto *p = (struct krt_proto *) P;
+@@ -688,13 +688,21 @@ krt_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *net,
+     case KPS_IDLE:
+     case KPS_PRUNING:
+       if (new && bmap_test(&p->seen_map, new->id))
+-	/* Already installed and seen in the kernel dump */
+-	return;
++	if (ch->debug & D_ROUTES)
++	{
++	  /* Already installed and seen in the kernel dump */
++	  log(L_TRACE "%s.%s: %N already in kernel",
++	      P->name, ch->name, net);
++	  return;
++	}
+ 
+       /* fall through */
+     case KPS_SCANNING:
+       /* Actually replace the route */
+       krt_replace_rte(p, net, new, old);
++      if (ch->debug & D_ROUTES)
++	log(L_TRACE "%s.%s: %N %s kernel",
++	    P->name, ch->name, net, old ? "replaced in" : "added to");
+       break;
+ 
+   }
+-- 
+GitLab
+
diff --git a/net/bird3/files/patch-03-BGP-fix-locking-order b/net/bird3/files/patch-03-BGP-fix-locking-order
new file mode 100644
index 000000000000..51b73c26f8f8
--- /dev/null
+++ b/net/bird3/files/patch-03-BGP-fix-locking-order
@@ -0,0 +1,176 @@
+From 6779e5da698feb9b9e02411859ad81885ba46c01 Mon Sep 17 00:00:00 2001
+From: Maria Matejka <mq@ucw.cz>
+Date: Fri, 20 Dec 2024 11:28:00 +0100
+Subject: [PATCH] BGP: fix locking order error on dynamic protocol spawn
+
+We missed that the protocol spawner violates the prescribed
+locking order. When the rtable level is locked, no new protocol can be
+started, thus we need to:
+
+* create the protocol from a clean mainloop context
+* in protocol start hook, take the socket
+
+Testsuite: cf-bgp-autopeer
+Fixes: #136
+
+Thanks to Job Snijders <job@fastly.com> for reporting:
+https://trubka.network.cz/pipermail/bird-users/2024-December/017980.html
+---
+ nest/proto.c    | 19 +++++++++++++++++++
+ nest/protocol.h |  2 ++
+ proto/bgp/bgp.c | 46 +++++++++++++++++++++++++++++++++++-----------
+ 3 files changed, 56 insertions(+), 11 deletions(-)
+
+diff --git a/nest/proto.c b/nest/proto.c
+index dded84f51..678697d69 100644
+--- nest/proto.c
++++ nest/proto.c
+@@ -1867,6 +1867,25 @@ proto_spawn(struct proto_config *cf, uint disabled)
+   return p;
+ }
+ 
++bool
++proto_disable(struct proto *p)
++{
++  ASSERT_DIE(birdloop_inside(&main_birdloop));
++  bool changed = !p->disabled;
++  p->disabled = 1;
++  proto_rethink_goal(p);
++  return changed;
++}
++
++bool
++proto_enable(struct proto *p)
++{
++  ASSERT_DIE(birdloop_inside(&main_birdloop));
++  bool changed = p->disabled;
++  p->disabled = 0;
++  proto_rethink_goal(p);
++  return changed;
++}
+ 
+ /**
+  * DOC: Graceful restart recovery
+diff --git a/nest/protocol.h b/nest/protocol.h
+index 25ed6f553..cf7ecb898 100644
+--- nest/protocol.h
++++ nest/protocol.h
+@@ -78,6 +78,8 @@ void proto_build(struct protocol *);	/* Called from protocol to register itself
+ void protos_preconfig(struct config *);
+ void protos_commit(struct config *new, struct config *old, int type);
+ struct proto * proto_spawn(struct proto_config *cf, uint disabled);
++bool proto_disable(struct proto *p);
++bool proto_enable(struct proto *p);
+ void protos_dump_all(struct dump_request *);
+ 
+ #define GA_UNKNOWN	0		/* Attribute not recognized */
+diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
+index 5fc2b5fff..3170e3a42 100644
+--- proto/bgp/bgp.c
++++ proto/bgp/bgp.c
+@@ -378,8 +378,6 @@ bgp_startup(struct bgp_proto *p)
+   if (p->postponed_sk)
+   {
+     /* Apply postponed incoming connection */
+-    sk_reloop(p->postponed_sk, p->p.loop);
+-
+     bgp_setup_conn(p, &p->incoming_conn);
+     bgp_setup_sk(&p->incoming_conn, p->postponed_sk);
+     bgp_send_open(&p->incoming_conn);
+@@ -583,6 +581,9 @@ bgp_graceful_close_conn(struct bgp_conn *conn, int subcode, byte *data, uint len
+ static void
+ bgp_down(struct bgp_proto *p)
+ {
++  /* Check that the dynamic BGP socket has been picked up */
++  ASSERT_DIE(p->postponed_sk == NULL);
++
+   if (bgp_start_state(p) > BSS_PREPARE)
+   {
+     bgp_setup_auth(p, 0);
+@@ -617,8 +618,8 @@ bgp_decision(void *vp)
+     bgp_down(p);
+ }
+ 
+-static struct bgp_proto *
+-bgp_spawn(struct bgp_proto *pp, ip_addr remote_ip)
++static void
++bgp_spawn(struct bgp_proto *pp, struct birdsock *sk)
+ {
+   struct symbol *sym;
+   char fmt[SYM_MAX_LEN];
+@@ -635,9 +636,16 @@ bgp_spawn(struct bgp_proto *pp, ip_addr remote_ip)
+   cfg_mem = NULL;
+ 
+   /* Just pass remote_ip to bgp_init() */
+-  ((struct bgp_config *) sym->proto)->remote_ip = remote_ip;
++  ((struct bgp_config *) sym->proto)->remote_ip = sk->daddr;
++
++  /* Create the protocol disabled initially */
++  SKIP_BACK_DECLARE(struct bgp_proto, p, p, proto_spawn(sym->proto, 1));
+ 
+-  return (void *) proto_spawn(sym->proto, 0);
++  /* Pass the socket */
++  p->postponed_sk = sk;
++
++  /* And enable the protocol */
++  proto_enable(&p->p);
+ }
+ 
+ void
+@@ -1489,10 +1497,15 @@ bgp_incoming_connection(sock *sk, uint dummy UNUSED)
+   /* For dynamic BGP, spawn new instance and postpone the socket */
+   if (bgp_is_dynamic(p))
+   {
+-    p = bgp_spawn(p, sk->daddr);
+-    p->postponed_sk = sk;
+-    rmove(sk, p->p.pool);
+-    goto leave;
++    UNLOCK_DOMAIN(rtable, bgp_listen_domain);
++
++    /* The dynamic protocol must be in the START state */
++    ASSERT_DIE(p->p.proto_state == PS_START);
++    birdloop_leave(p->p.loop);
++
++    /* Now we have a clean mainloop */
++    bgp_spawn(p, sk);
++    return 0;
+   }
+ 
+   rmove(sk, p->p.pool);
+@@ -1806,7 +1819,6 @@ bgp_start(struct proto *P)
+   p->incoming_conn.state = BS_IDLE;
+   p->neigh = NULL;
+   p->bfd_req = NULL;
+-  p->postponed_sk = NULL;
+   p->gr_ready = 0;
+   p->gr_active_num = 0;
+ 
+@@ -1848,6 +1860,16 @@ bgp_start(struct proto *P)
+       channel_graceful_restart_lock(&c->c);
+   }
+ 
++  /* Now it's the last chance to move the postponed socket to this BGP,
++   * as bgp_start is the only hook running from main loop. */
++  if (p->postponed_sk)
++  {
++    LOCK_DOMAIN(rtable, bgp_listen_domain);
++    rmove(p->postponed_sk, p->p.pool);
++    sk_reloop(p->postponed_sk, p->p.loop);
++    UNLOCK_DOMAIN(rtable, bgp_listen_domain);
++  }
++
+   /*
+    * Before attempting to create the connection, we need to lock the port,
+    * so that we are the only instance attempting to talk with that neighbor.
+@@ -1999,6 +2021,8 @@ bgp_init(struct proto_config *CF)
+   p->remote_ip = cf->remote_ip;
+   p->remote_as = cf->remote_as;
+ 
++  p->postponed_sk = NULL;
++
+   /* Hack: We use cf->remote_ip just to pass remote_ip from bgp_spawn() */
+   if (cf->c.parent)
+     cf->remote_ip = IPA_NONE;
+-- 
+GitLab
+
diff --git a/net/bird3/files/patch-04-BFD-Fix-session-locking-order b/net/bird3/files/patch-04-BFD-Fix-session-locking-order
new file mode 100644
index 000000000000..3f5500500691
--- /dev/null
+++ b/net/bird3/files/patch-04-BFD-Fix-session-locking-order
@@ -0,0 +1,400 @@
+From 83495362789d961914c4bfaa590e31cb17370ed0 Mon Sep 17 00:00:00 2001
+From: Maria Matejka <mq@ucw.cz>
+Date: Sat, 21 Dec 2024 19:02:22 +0100
+Subject: [PATCH] BFD: Fix session reconfiguration locking order
+
+The sessions have to be updated asynchronously to avoid
+cross-locking between protocols.
+
+Testsuite: cf-ibgp-bfd-switch, cf-ibgp-multi-bfd-auth
+Fixes: #139
+
+Thanks to Daniel Suchy <danny@danysek.cz> for reporting:
+https://trubka.network.cz/pipermail/bird-users/2024-December/017984.html
+---
+ nest/bfd.h          |   7 ++-
+ proto/bfd/bfd.c     | 144 +++++++++++++++++++++++---------------------
+ proto/bfd/bfd.h     |  21 +------
+ proto/bfd/config.Y  |  42 +++++--------
+ proto/bfd/packets.c |   4 +-
+ 5 files changed, 98 insertions(+), 120 deletions(-)
+
+diff --git a/nest/bfd.h b/nest/bfd.h
+index 5dacff5d7..c046152f8 100644
+--- nest/bfd.h
++++ nest/bfd.h
+@@ -18,8 +18,11 @@ struct bfd_options {
+   u32 min_tx_int;
+   u32 idle_tx_int;
+   u8 multiplier;
+-  u8 passive;
+-  u8 passive_set;
++  PACKED enum bfd_opt_passive {
++    BFD_OPT_PASSIVE_UNKNOWN = 0,
++    BFD_OPT_PASSIVE,
++    BFD_OPT_NOT_PASSIVE,
++  } passive;
+   u8 mode;
+   u8 auth_type;				/* Authentication type (BFD_AUTH_*) */
+   list *passwords;			/* Passwords for authentication */
+diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
+index 34f992b93..4997f803a 100644
+--- proto/bfd/bfd.c
++++ proto/bfd/bfd.c
+@@ -172,17 +172,17 @@ static void bfd_free_iface(struct bfd_iface *ifa);
+  *	BFD sessions
+  */
+ 
+-static inline struct bfd_session_config
+-bfd_merge_options(const struct bfd_iface_config *cf, const struct bfd_options *opts)
++static inline struct bfd_options
++bfd_merge_options(const struct bfd_options *bottom, const struct bfd_options *top)
+ {
+-  return (struct bfd_session_config) {
+-    .min_rx_int = opts->min_rx_int ?: cf->min_rx_int,
+-    .min_tx_int = opts->min_tx_int ?: cf->min_tx_int,
+-    .idle_tx_int = opts->idle_tx_int ?: cf->idle_tx_int,
+-    .multiplier = opts->multiplier ?: cf->multiplier,
+-    .passive = opts->passive_set ? opts->passive : cf->passive,
+-    .auth_type = opts->auth_type ?: cf->auth_type,
+-    .passwords = opts->passwords ?: cf->passwords,
++  return (struct bfd_options) {
++    .min_rx_int = top->min_rx_int ?: bottom->min_rx_int,
++    .min_tx_int = top->min_tx_int ?: bottom->min_tx_int,
++    .idle_tx_int = top->idle_tx_int ?: bottom->idle_tx_int,
++    .multiplier = top->multiplier ?: bottom->multiplier,
++    .passive = top->passive ?: bottom->passive,
++    .auth_type = top->auth_type ?: bottom->auth_type,
++    .passwords = top->passwords ?: bottom->passwords,
+   };
+ }
+ 
+@@ -478,7 +478,7 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
+   HASH_INSERT(p->session_hash_id, HASH_ID, s);
+   HASH_INSERT(p->session_hash_ip, HASH_IP, s);
+ 
+-  s->cf = bfd_merge_options(ifa->cf, opts);
++  s->cf = bfd_merge_options(&ifa->cf->opts, opts);
+ 
+   /* Initialization of state variables - see RFC 5880 6.8.1 */
+   s->loc_state = BFD_STATE_DOWN;
+@@ -561,26 +561,58 @@ bfd_remove_session(struct bfd_proto *p, struct bfd_session *s)
+   birdloop_leave(p->p.loop);
+ }
+ 
++struct bfd_reconfigure_sessions_deferred_call {
++  struct deferred_call dc;
++  struct bfd_proto *p;
++  config_ref old_config;
++};
++
+ static void
+-bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s)
++bfd_reconfigure_sessions(struct deferred_call *dc)
+ {
+-  if (EMPTY_LIST(s->request_list))
+-    return;
++  SKIP_BACK_DECLARE(struct bfd_reconfigure_sessions_deferred_call,
++      brsdc, dc, dc);
+ 
+-  ASSERT_DIE(birdloop_inside(p->p.loop));
++  struct bfd_proto *p = brsdc->p;
++  birdloop_enter(p->p.loop);
+ 
+-  SKIP_BACK_DECLARE(struct bfd_request, req, n, HEAD(s->request_list));
+-  s->cf = bfd_merge_options(s->ifa->cf, &req->opts);
++  HASH_WALK(p->session_hash_id, next_id, s)
++  {
++    if (!EMPTY_LIST(s->request_list))
++    {
++      SKIP_BACK_DECLARE(struct bfd_request, req, n, HEAD(s->request_list));
++      struct bfd_options opts = bfd_merge_options(&s->ifa->cf->opts, &req->opts);
+ 
+-  u32 tx = (s->loc_state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int;
+-  bfd_session_set_min_tx(s, tx);
+-  bfd_session_set_min_rx(s, s->cf.min_rx_int);
+-  s->detect_mult = s->cf.multiplier;
+-  s->passive = s->cf.passive;
++#define CHK(x)	(opts.x != s->cf.x) ||
++      bool reload = MACRO_FOREACH(CHK,
++	  min_rx_int,
++	  min_tx_int,
++	  idle_tx_int,
++	  multiplier,
++	  passive) false; /* terminating the || chain */
++#undef CHK
+ 
+-  bfd_session_control_tx_timer(s, 0);
++      s->cf = opts;
++
++      if (reload)
++      {
++	u32 tx = (s->loc_state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int;
++	bfd_session_set_min_tx(s, tx);
++	bfd_session_set_min_rx(s, s->cf.min_rx_int);
++	s->detect_mult = s->cf.multiplier;
++	s->passive = s->cf.passive;
++
++	bfd_session_control_tx_timer(s, 0);
++
++	TRACE(D_EVENTS, "Session to %I reconfigured", s->addr);
++      }
++    }
++  }
++  HASH_WALK_END;
++  birdloop_leave(p->p.loop);
+ 
+-  TRACE(D_EVENTS, "Session to %I reconfigured", s->addr);
++  /* Now the config is clean */
++  OBSREF_CLEAR(brsdc->old_config);
+ }
+ 
+ 
+@@ -589,10 +621,12 @@ bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s)
+  */
+ 
+ static struct bfd_iface_config bfd_default_iface = {
+-  .min_rx_int = BFD_DEFAULT_MIN_RX_INT,
+-  .min_tx_int = BFD_DEFAULT_MIN_TX_INT,
+-  .idle_tx_int = BFD_DEFAULT_IDLE_TX_INT,
+-  .multiplier = BFD_DEFAULT_MULTIPLIER,
++  .opts = {
++    .min_rx_int = BFD_DEFAULT_MIN_RX_INT,
++    .min_tx_int = BFD_DEFAULT_MIN_TX_INT,
++    .idle_tx_int = BFD_DEFAULT_IDLE_TX_INT,
++    .multiplier = BFD_DEFAULT_MULTIPLIER,
++  },
+ };
+ 
+ static inline struct bfd_iface_config *
+@@ -650,24 +684,6 @@ bfd_free_iface(struct bfd_iface *ifa)
+   mb_free(ifa);
+ }
+ 
+-static void
+-bfd_reconfigure_iface(struct bfd_proto *p UNUSED, struct bfd_iface *ifa, struct bfd_config *nc)
+-{
+-  struct bfd_iface_config *new = bfd_find_iface_config(nc, ifa->iface);
+-  struct bfd_iface_config *old = ifa->cf;
+-
+-  /* Check options that are handled in bfd_reconfigure_session() */
+-  ifa->changed =
+-    (new->min_rx_int != old->min_rx_int) ||
+-    (new->min_tx_int != old->min_tx_int) ||
+-    (new->idle_tx_int != old->idle_tx_int) ||
+-    (new->multiplier != old->multiplier) ||
+-    (new->passive != old->passive);
+-
+-  /* This should be probably changed to not access ifa->cf from the BFD thread */
+-  ifa->cf = new;
+-}
+-
+ 
+ /*
+  *	BFD requests
+@@ -900,20 +916,7 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
+ void
+ bfd_update_request(struct bfd_request *req, const struct bfd_options *opts)
+ {
+-  struct bfd_session *s = req->session;
+-
+-  if (!memcmp(opts, &req->opts, sizeof(const struct bfd_options)))
+-    return;
+-
+   req->opts = *opts;
+-
+-  if (s)
+-  {
+-    struct bfd_proto *p = s->ifa->bfd;
+-    birdloop_enter(p->p.loop);
+-    bfd_reconfigure_session(p, s);
+-    birdloop_leave(p->p.loop);
+-  }
+ }
+ 
+ static void
+@@ -1193,21 +1196,22 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
+       (new->zero_udp6_checksum_rx != old->zero_udp6_checksum_rx))
+     return 0;
+ 
+-  birdloop_mask_wakeups(p->p.loop);
+-
+   WALK_LIST(ifa, p->iface_list)
+-    bfd_reconfigure_iface(p, ifa, new);
+-
+-  HASH_WALK(p->session_hash_id, next_id, s)
+-  {
+-    if (s->ifa->changed)
+-      bfd_reconfigure_session(p, s);
+-  }
+-  HASH_WALK_END;
++    ifa->cf = bfd_find_iface_config(new, ifa->iface);
+ 
+   bfd_reconfigure_neighbors(p, new);
+ 
+-  birdloop_unmask_wakeups(p->p.loop);
++  /* Sessions get reconfigured after all the config is applied */
++  struct bfd_reconfigure_sessions_deferred_call brsdc = {
++    .dc.hook = bfd_reconfigure_sessions,
++    .p = p,
++  };
++  SKIP_BACK_DECLARE(struct bfd_reconfigure_sessions_deferred_call,
++      brsdcp, dc, defer_call(&brsdc.dc, sizeof brsdc));
++
++  /* We need to keep the old config alive until all the sessions get
++   * reconfigured */
++  OBSREF_SET(brsdcp->old_config, P->cf->global);
+ 
+   return 1;
+ }
+diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h
+index 578ce8755..107829b72 100644
+--- proto/bfd/bfd.h
++++ proto/bfd/bfd.h
+@@ -54,24 +54,7 @@ struct bfd_config
+ struct bfd_iface_config
+ {
+   struct iface_patt i;
+-  u32 min_rx_int;
+-  u32 min_tx_int;
+-  u32 idle_tx_int;
+-  u8 multiplier;
+-  u8 passive;
+-  u8 auth_type;				/* Authentication type (BFD_AUTH_*) */
+-  list *passwords;			/* Passwords for authentication */
+-};
+-
+-struct bfd_session_config
+-{
+-  u32 min_rx_int;
+-  u32 min_tx_int;
+-  u32 idle_tx_int;
+-  u8 multiplier;
+-  u8 passive;
+-  u8 auth_type;				/* Authentication type (BFD_AUTH_*) */
+-  list *passwords;			/* Passwords for authentication */
++  struct bfd_options opts;
+ };
+ 
+ struct bfd_neighbor
+@@ -146,7 +129,7 @@ struct bfd_session
+   u32 loc_id;				/* Local session ID (local discriminator) */
+   u32 rem_id;				/* Remote session ID (remote discriminator) */
+ 
+-  struct bfd_session_config cf;		/* Static configuration parameters */
++  struct bfd_options cf;		/* Static configuration parameters */
+ 
+   u32 des_min_tx_int;			/* Desired min rx interval, local option */
+   u32 des_min_tx_new;			/* Used for des_min_tx_int change */
+diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
+index 9e9919c4e..56d1ffac4 100644
+--- proto/bfd/config.Y
++++ proto/bfd/config.Y
+@@ -86,44 +86,37 @@ bfd_iface_start:
+   add_tail(&BFD_CFG->patt_list, NODE this_ipatt);
+   init_list(&this_ipatt->ipn_list);
+ 
+-  BFD_IFACE->min_rx_int = BFD_DEFAULT_MIN_RX_INT;
+-  BFD_IFACE->min_tx_int = BFD_DEFAULT_MIN_TX_INT;
+-  BFD_IFACE->idle_tx_int = BFD_DEFAULT_IDLE_TX_INT;
+-  BFD_IFACE->multiplier = BFD_DEFAULT_MULTIPLIER;
++  this_bfd_opts = &BFD_IFACE->opts;
++
++  this_bfd_opts->min_rx_int = BFD_DEFAULT_MIN_RX_INT;
++  this_bfd_opts->min_tx_int = BFD_DEFAULT_MIN_TX_INT;
++  this_bfd_opts->idle_tx_int = BFD_DEFAULT_IDLE_TX_INT;
++  this_bfd_opts->multiplier = BFD_DEFAULT_MULTIPLIER;
+ 
+   reset_passwords();
+ };
+ 
+ bfd_iface_finish:
+ {
+-  BFD_IFACE->passwords = get_passwords();
++  this_bfd_opts->passwords = get_passwords();
+ 
+-  if (!BFD_IFACE->auth_type != !BFD_IFACE->passwords)
++  if (!this_bfd_opts->auth_type != !this_bfd_opts->passwords)
+     cf_warn("Authentication and password options should be used together");
+ 
+-  if (BFD_IFACE->passwords)
++  if (this_bfd_opts->passwords)
+   {
+     struct password_item *pass;
+-    WALK_LIST(pass, *BFD_IFACE->passwords)
++    WALK_LIST(pass, *this_bfd_opts->passwords)
+     {
+       if (pass->alg)
+         cf_error("Password algorithm option not available in BFD protocol");
+ 
+-      pass->alg = bfd_auth_type_to_hash_alg[BFD_IFACE->auth_type];
++      pass->alg = bfd_auth_type_to_hash_alg[this_bfd_opts->auth_type];
+     }
+   }
+-};
+ 
+-bfd_iface_item:
+-   INTERVAL expr_us { BFD_IFACE->min_rx_int = BFD_IFACE->min_tx_int = $2; }
+- | MIN RX INTERVAL expr_us { BFD_IFACE->min_rx_int = $4; }
+- | MIN TX INTERVAL expr_us { BFD_IFACE->min_tx_int = $4; }
+- | IDLE TX INTERVAL expr_us { BFD_IFACE->idle_tx_int = $4; }
+- | MULTIPLIER expr { BFD_IFACE->multiplier = $2; }
+- | PASSIVE bool { BFD_IFACE->passive = $2; }
+- | AUTHENTICATION bfd_auth_type { BFD_IFACE->auth_type = $2; }
+- | password_list {}
+- ;
++  this_bfd_opts = NULL;
++};
+ 
+ bfd_auth_type:
+    NONE			 { $$ = BFD_AUTH_NONE; }
+@@ -134,14 +127,9 @@ bfd_auth_type:
+  | METICULOUS KEYED SHA1 { $$ = BFD_AUTH_METICULOUS_KEYED_SHA1; }
+  ;
+ 
+-bfd_iface_opts:
+-   /* empty */
+- | bfd_iface_opts bfd_iface_item ';'
+- ;
+-
+ bfd_iface_opt_list:
+    /* empty */
+- | '{' bfd_iface_opts '}'
++ | '{' bfd_items '}'
+  ;
+ 
+ bfd_iface:
+@@ -194,7 +182,7 @@ bfd_item:
+  | MIN TX INTERVAL expr_us { this_bfd_opts->min_tx_int = $4; }
+  | IDLE TX INTERVAL expr_us { this_bfd_opts->idle_tx_int = $4; }
+  | MULTIPLIER expr { this_bfd_opts->multiplier = $2; }
+- | PASSIVE bool { this_bfd_opts->passive = $2; this_bfd_opts->passive_set = 1; }
++ | PASSIVE bool { this_bfd_opts->passive = $2 ? BFD_OPT_PASSIVE : BFD_OPT_NOT_PASSIVE; }
+  | GRACEFUL { this_bfd_opts->mode = BGP_BFD_GRACEFUL; }
+  | AUTHENTICATION bfd_auth_type { this_bfd_opts->auth_type = $2; }
+  | password_list {}
+diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c
+index 1ceb470c1..f8bd63d73 100644
+--- proto/bfd/packets.c
++++ proto/bfd/packets.c
+@@ -109,7 +109,7 @@ const u8 bfd_auth_type_to_hash_alg[] = {
+ static void
+ bfd_fill_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_ctl_packet *pkt)
+ {
+-  struct bfd_session_config *cf = &s->cf;
++  struct bfd_options *cf = &s->cf;
+   struct password_item *pass = password_find(cf->passwords, 0);
+   uint meticulous = 0;
+ 
+@@ -179,7 +179,7 @@ bfd_fill_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_c
+ static int
+ bfd_check_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_ctl_packet *pkt)
+ {
+-  struct bfd_session_config *cf = &s->cf;
++  struct bfd_options *cf = &s->cf;
+   const char *err_dsc = NULL;
+   uint err_val = 0;
+   uint auth_type = 0;
+-- 
+GitLab
+
diff --git a/net/bird3/files/patch-05-mainloop-dropped-old-socket b/net/bird3/files/patch-05-mainloop-dropped-old-socket
new file mode 100644
index 000000000000..eea4d1d26af2
--- /dev/null
+++ b/net/bird3/files/patch-05-mainloop-dropped-old-socket
@@ -0,0 +1,86 @@
+From 3d1f19e335f55c8cfa3cb7ca9d7b88ca03173d8e Mon Sep 17 00:00:00 2001
+From: Maria Matejka <mq@ucw.cz>
+Date: Sun, 22 Dec 2024 21:32:28 +0100
+Subject: [PATCH] Mainloop: Dropped old socket prioritization magic
+
+This is now done in worker threads and the mainloop needs to do other things,
+most notably kernel and CLI, with less overhead of repeatedly checking poll.
+---
+ sysdep/unix/io-loop.c |  2 +-
+ sysdep/unix/io.c      | 21 +++++++--------------
+ 2 files changed, 8 insertions(+), 15 deletions(-)
+
+diff --git a/sysdep/unix/io-loop.c b/sysdep/unix/io-loop.c
+index f69189e06..a72c69a03 100644
+--- sysdep/unix/io-loop.c
++++ sysdep/unix/io-loop.c
+@@ -1403,7 +1403,7 @@ bool task_still_in_limit(void)
+ {
+   static u64 main_counter = 0;
+   if (this_birdloop == &main_birdloop)
+-    return (++main_counter % 2048);	/* This is a hack because of no accounting in mainloop */
++    return (++main_counter % 512);	/* This is a hack because of no accounting in mainloop */
+   else
+     return ns_now() < account_last + this_thread->max_loop_time_ns;
+ }
+diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
+index f9785c074..51395e1e9 100644
+--- sysdep/unix/io.c
++++ sysdep/unix/io.c
+@@ -53,14 +53,15 @@
+ 
+ /* Maximum number of calls of tx handler for one socket in one
+  * poll iteration. Should be small enough to not monopolize CPU by
+- * one protocol instance.
++ * one protocol instance. But as most of the problems are now offloaded
++ * to worker threads, too low values may actually bring problems with
++ * latency.
+  */
+-#define MAX_STEPS 4
++#define MAX_STEPS 2048
+ 
+ /* Maximum number of calls of rx handler for all sockets in one poll
+-   iteration. RX callbacks are often much more costly so we limit
+-   this to gen small latencies */
+-#define MAX_RX_STEPS 4
++   iteration. RX callbacks are often a little bit more costly. */
++#define MAX_RX_STEPS 512
+ 
+ 
+ /*
+@@ -2581,8 +2582,6 @@ io_init(void)
+   srandom((uint) (now ^ (now >> 32)));
+ }
+ 
+-static int short_loops = 0;
+-#define SHORT_LOOP_MAX 10
+ #define WORK_EVENTS_MAX 10
+ 
+ sock *stored_sock;
+@@ -2670,10 +2669,9 @@ io_loop(void)
*** 1461 LINES SKIPPED ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202501092208.509M8E3C053936>