From nobody Thu Oct 9 12:21:29 2025 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4cj8B21Rl8z6BqNd; Thu, 09 Oct 2025 12:21:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4cj8B20yGyz3QhY; Thu, 09 Oct 2025 12:21:30 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760012490; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KeZesa9jNUBydlg2sl9HEBjOO6QmsRDKRmmN6QhieBY=; b=i/qakdSH+OZOzaKu+WNm4MLNxmPwzO0CHyojCPQj3mPUEGX0LAZ7LR2MiXdo413Qg/f7Gt rqw2kuVDYUPSqdkMNsTVNIwjU0Of9S6UOncJFr40jSoGbZyDKkq/qotqhSMMsuHyg8yzJS ZciF962dHUo1Yp9A2bmjVAM5Tmqrv0vEc0Xs/0yn4zMpyHhtdE5AOqRXrFnvXsbgH8yq2U Yx2ipF1E3hwU+BVLjdWiC6WPqN7z9s9Pf4mAsmr8f9BBAtLKygJgjWq+TvmVIscbDeD+Ty QOfnF5NgL1bQXqlZue2RO9DZQWWkm8teUhgGEO0dUN7AwlVyHCAfRIQG/E9MiQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1760012490; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=KeZesa9jNUBydlg2sl9HEBjOO6QmsRDKRmmN6QhieBY=; b=R6LbCX278LyZ7IreisOLN+PQ93/1eHr8yP9k5UsNIrP7Wi4peeSu6nbzfOVZP+kr6s4Dqk x1iABxfa/7w5FgEMtiDbT9pU5R4cSmL9Q7HiJiaoLme8ttWOG+IUhlaBJMn6BighUawE/A CBjx+b2DdUBEuFnUT6LAkWaSxzbz7LqQQVQ5fP2nXA0mEPIABMtFstO/rj5UjvphRKWyrG Yp5G3RV72/GqymXNkQP9SheNtHZZ94iiUtChxcsaX27JxIeBiShken/ZWRL3FO/HD9shsn 6srCM0S4TyYhbyWjEb1XrL9mkV0vHqUV4PMJi1adUNhXcbFfPd61oSeS9IeuXA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1760012490; a=rsa-sha256; cv=none; b=DqEOnPQ4UX4tdYiGNnLuPBKwl5hXku5T7U163JziEJ591Bfa0W3uUcMWu6AOqLofiieNU8 2z+R//dlWJOjJdWuFC0ox6yjNsQAfjWqaxuxH5bmKJ67vNVFpw9gNlxfcQq+7gOj4xcm/6 +ODy9g33x/WfoFY8ibDO51xvL6C833MDZtsWPMbN3nMmISorELadh4Qe3yDeYG0O+Pc34w nd8t/j4dC6SnsuaT3eIO95hqc7gC/8WbdcEZJ1fiIUIcBTFPd7VFAZRFLFaP89n/VPPIST vqEBOKFKxvBJ4U1QDTYcRvT30q7WaBRLC2C0kHOY/R0JlhYl5pwfjzmLvW4C7Q== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4cj8B20LTsz2Y0; Thu, 09 Oct 2025 12:21:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 599CLTaf046548; Thu, 9 Oct 2025 12:21:29 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 599CLT2C046545; Thu, 9 Oct 2025 12:21:29 GMT (envelope-from git) Date: Thu, 9 Oct 2025 12:21:29 GMT Message-Id: <202510091221.599CLT2C046545@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: df70662f4704 - stable/15 - rc: Teach netwait to wait for DAD List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: df70662f4704f432b00b5a8b4acd7f12a2deffa3 Auto-Submitted: auto-generated The branch stable/15 has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=df70662f4704f432b00b5a8b4acd7f12a2deffa3 commit df70662f4704f432b00b5a8b4acd7f12a2deffa3 Author: Dag-Erling Smørgrav AuthorDate: 2025-10-02 09:28:05 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2025-10-09 12:16:04 +0000 rc: Teach netwait to wait for DAD In some configurations, especially in jails, it is possible for the system to boot so fast that we end up launching daemons while duplicate address detection is still ongoing. If that happens, said daemons may fail to bind to IPv6 addresses, as they are still tentative. Teach the netwait service to wait (up to 10 seconds, by default) for the tentative flag to vanish. MFC after: 1 week Reviewed by: olce Differential Revision: https://reviews.freebsd.org/D51889 (cherry picked from commit 5ead817c3b7af6d6b5fea222ab144db2c3167b22) rc: Improve netwait DAD logic Disable if IPv6 is not supported, and instead of 10 seconds, default to one more than the value of net.inet6.ip6.dad_count. Fixes: 5ead817c3b7a ("rc: Teach netwait to wait for DAD") Reviewed by: bz Differential Revision: https://reviews.freebsd.org/D52905 (cherry picked from commit ec6ad605ecea5c4a76d2e744df0265cc3f3a01b9) --- libexec/rc/rc.conf | 3 ++ libexec/rc/rc.d/netwait | 86 ++++++++++++++++++++++++++++++++++-------------- share/man/man5/rc.conf.5 | 27 ++++++++++----- 3 files changed, 84 insertions(+), 32 deletions(-) diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf index 9da2aef44d3d..96dd420d0322 100644 --- a/libexec/rc/rc.conf +++ b/libexec/rc/rc.conf @@ -500,6 +500,9 @@ netwait_enable="NO" # Enable rc.d/netwait (or NO) netwait_timeout="60" # Total number of seconds to perform pings. #netwait_if="" # Wait for active link on each intf in this list. netwait_if_timeout="30" # Total number of seconds to monitor link state. +netwait_dad="NO" # Wait for DAD to complete +netwait_dad_timeout="" # Total number of seconds to wait for DAD, zero + # or unset to autodetect ### Miscellaneous network options: ### icmp_bmcastecho="NO" # respond to broadcast ping packets diff --git a/libexec/rc/rc.d/netwait b/libexec/rc/rc.d/netwait index 3f374806d97c..05874552cf1c 100755 --- a/libexec/rc/rc.d/netwait +++ b/libexec/rc/rc.d/netwait @@ -2,12 +2,14 @@ # # PROVIDE: netwait # REQUIRE: devd ipfw pf routing -# KEYWORD: nojail # -# The netwait script helps handle two situations: +# The netwait script helps handle three situations: # - Systems with USB or other late-attaching network hardware which # is initialized by devd events. The script waits for all the # interfaces named in the netwait_if list to appear. +# - Systems with IPv6 addresses, especially jails, where we need to +# wait for DAD to complete before starting daemons, as they will +# otherwise fail to bind to IN6ADDR_ANY. # - Systems with statically-configured IP addresses in rc.conf(5). # The IP addresses in the netwait_ip list are pinged. The script # waits for any single IP in the list to respond to the ping. If your @@ -29,28 +31,38 @@ netwait_start() { local ip rc count output link wait_if got_if any_error - if [ -z "${netwait_if}" ] && [ -z "${netwait_ip}" ]; then - err 1 "No interface or IP addresses listed, nothing to wait for" + if [ -z "${netwait_if}" ] && [ -z "${netwait_ip}" ] && + ! checkyesno netwait_dad ; then + err 1 "Nothing to wait for" fi - if [ ${netwait_timeout} -lt 1 ]; then + if ! [ "${netwait_if_timeout:=0}" -ge 1 ]; then + err 1 "netwait_if_timeout must be >= 1" + fi + if ! check_kern_features inet6; then + netwait_dad="NO" + elif ! [ "${netwait_dad_timeout:=0}" -ge 1 ]; then + netwait_dad_timeout=$(($(sysctl -n net.inet6.ip6.dad_count)+1)) + fi + if ! [ "${netwait_timeout:=0}" -ge 1 ]; then err 1 "netwait_timeout must be >= 1" fi + any_error=false + if [ -n "${netwait_if}" ]; then - any_error=0 for wait_if in ${netwait_if}; do echo -n "Waiting for ${wait_if}" link="" - got_if=0 + got_if=false count=1 - # Handle SIGINT (Ctrl-C); force abort of while() loop + # Handle SIGINT (Ctrl-C); force abort of while loop trap break SIGINT while [ ${count} -le ${netwait_if_timeout} ]; do if output=`/sbin/ifconfig ${wait_if} 2>/dev/null`; then - if [ ${got_if} -eq 0 ]; then + if ! ${got_if}; then echo -n ", interface present" - got_if=1 + got_if=true fi link=`expr "${output}" : '.*[[:blank:]]status: \(no carrier\)'` if [ -z "${link}" ]; then @@ -63,22 +75,45 @@ netwait_start() done # Restore default SIGINT handler trap - SIGINT - if [ ${got_if} -eq 0 ]; then + if ! ${got_if}; then echo ", wait failed: interface never appeared." - any_error=1 + any_error=true elif [ -n "${link}" ]; then echo ", wait failed: interface still has no link." - any_error=1 + any_error=true fi done - if [ ${any_error} -eq 1 ]; then - warn "Continuing with startup, but be aware you may not have " - warn "a fully functional networking layer at this point." - fi fi + if checkyesno netwait_dad; then + got_dad=false + # Handle SIGINT (Ctrl-C); force abort of while loop + trap break SIGINT + + echo -n "Waiting for DAD to complete" + count=1 + while [ ${count} -le ${netwait_dad_timeout} ]; do + if ! ifconfig | grep -q 'inet6.*tentative'; then + echo ', done.' + got_dad=true + break + fi + sleep 1 + count=$((count+1)) + done + + # Restore default SIGINT handler + trap - SIGINT + + if ! ${got_dad}; then + echo ', timed out.' + any_error=true + fi + fi + if [ -n "${netwait_ip}" ]; then - # Handle SIGINT (Ctrl-C); force abort of for() loop + got_ip=false + # Handle SIGINT (Ctrl-C); force abort of for loop trap break SIGINT for ip in ${netwait_ip}; do @@ -90,11 +125,9 @@ netwait_start() rc=$? if [ $rc -eq 0 ]; then - # Restore default SIGINT handler - trap - SIGINT - echo ', got response.' - return + got_ip=false + break 2 fi count=$((count+1)) done @@ -104,10 +137,15 @@ netwait_start() # Restore default SIGINT handler trap - SIGINT - warn "Exhausted IP list. Continuing with startup, but be aware you may" - warn "not have a fully functional networking layer at this point." + if ! ${got_ip}; then + any_error=true + fi fi + if ${any_error}; then + warn "Continuing with startup, but be aware you may not have " + warn "a fully functional networking layer at this point." + fi } load_rc_config $name diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5 index b8c72fc07083..edbfa937f8df 100644 --- a/share/man/man5/rc.conf.5 +++ b/share/man/man5/rc.conf.5 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 25, 2025 +.Dd October 5, 2025 .Dt RC.CONF 5 .Os .Sh NAME @@ -4563,20 +4563,16 @@ If set to .Dq Li YES , delays the start of network-reliant services until .Va netwait_if -is up and ICMP packets to a destination defined in +is up, duplicate address discovery (DAD) has completed, and ICMP +packets to a destination defined in .Va netwait_ip are flowing. -Link state is examined first, followed by +Link state is examined first, followed by DAD, then .Dq Li pinging an IP address to verify network usability. If no destination can be reached or timeouts are exceeded, network services are started anyway with no guarantee that the network is usable. -Use of this variable requires both -.Va netwait_ip -and -.Va netwait_if -to be set. .It Va netwait_ip .Pq Vt str Empty by default. @@ -4612,6 +4608,21 @@ interface if desired. Defines the total number of seconds to wait for link to become usable, polled at a 1-second interval. The default is 30. +.It Va netwait_dad +.Pq Vt str +Set to +.Dq Li NO +by default. +Set to +.Dq Li YES +to enable waiting for DAD to complete. +.It Va netwait_dad_timeout +.Pq Vt int +Unset by default. +Indicates the maximum number of seconds to wait for DAD to complete. +If zero or unset, the timeout will be one more than the value of the +.Va net.inet6.ip6.dad_count +sysctl variable. .It Va rctl_enable .Pq Vt bool If set to