Index | Thread | Search

From:
Yuichiro NAITO <naito.yuichiro@gmail.com>
Subject:
carp: advbase takes 1 more tick than expected.
To:
tech@openbsd.org
Date:
Wed, 4 Mar 2026 11:22:39 +0900

Download raw body.

Thread
  • Yuichiro NAITO:

    carp: advbase takes 1 more tick than expected.

I see the following packet capture in a carp interface. The tcpdump '-tttt'
option shows the interval between packets. The interval is mostly around
1.01 sec although the default advbase is 1 sec. This has been happening
since OpenBSD 7.8. I don't see this prior to 7.8.

# tcpdump -n -i carp0 -tttt
tcpdump: listening on carp0, link-type EN10MB
1772589732.352164 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.009992 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.010001 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.010000 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.009999 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.009988 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.010012 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.010006 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.010002 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.010014 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.009957 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
^C
12 packets received by filter
0 packets dropped by kernel


The carp implementation calls the timeout_add_usec(9) for the advert interval.
It ensures that the specified timeout is rounded up to the tick interval
(= 10 msec).  Then calls the timeout_add_ticks(9). The timeout_add_ticks(9) adds
an extra 1 tick if the argument is less than INT_MAX. Of course, 1 second is 100
ticks, less than INT_MAX, so the timeout value always adds 1 tick. 

Just calling timeout_add(9) instead of timeout_add_ticks(9) fixes this issue. The
to_tick value is already adjusted, timeout_add(9) will wait for the proper time.

The same thing happens on timeout_add_nsec(9), we need to fix both of them.

diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 903b7b9de6e..35ab0f1f259 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -418,7 +418,7 @@ timeout_add_usec(struct timeout *to, uint64_t usecs)
 
 	to_ticks = (usecs + (tick - 1)) / tick;
 
-	return timeout_add_ticks(to, to_ticks);
+	return timeout_add(to, to_ticks);
 }
 
 int
@@ -431,7 +431,7 @@ timeout_add_nsec(struct timeout *to, uint64_t nsecs)
 
 	to_ticks = (nsecs + (tick_nsec - 1)) / tick_nsec;
 
-	return timeout_add_ticks(to, to_ticks);
+	return timeout_add(to, to_ticks);
 }
 
 int

After applying this patch, I see the following packet capture.

# tcpdump -n -i carp0 -tttt 
tcpdump: listening on carp0, link-type EN10MB
1772589982.073241 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
0.999978 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.000096 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
0.999845 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.000067 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.000069 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
1.000006 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
0.999992 CARPv2-advertise 36: vhid=1 advbase=1 advskew=0 demote=0 (DF) [tos 0x10]
^C
8 packets received by filter
0 packets dropped by kernel

-- 
Yuichiro NAITO (naito.yuichro@gmail.com)