Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 4 Oct 2025 16:23:22 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        =?UTF-8?Q?Dag-Erling_Sm=C3=B8rgrav?= <des@FreeBSD.org>
Cc:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org,  dev-commits-src-main@FreeBSD.org
Subject:   Re: git: 5ead817c3b7a - main - rc: Teach netwait to wait for  DAD
Message-ID:  <2r6r204q-qs32-70pq-rqn1-5s4p54r1385@mnoonqbm.arg>
In-Reply-To: <202510020932.5929WpJi067756@gitrepo.freebsd.org>
References:  <202510020932.5929WpJi067756@gitrepo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
  This message is in MIME format.  The first part should be readable text,
  while the remaining parts are likely unreadable without MIME-aware tools.

--0-768921551-1759595003=:11296
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 8BIT

On Thu, 2 Oct 2025, Dag-Erling Smørgrav wrote:

> The branch main has been updated by des:
>
> URL: https://cgit.FreeBSD.org/src/commit/?id=5ead817c3b7af6d6b5fea222ab144db2c3167b22
>
> commit 5ead817c3b7af6d6b5fea222ab144db2c3167b22
> Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
> AuthorDate: 2025-10-02 09:28:05 +0000
> Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
> CommitDate: 2025-10-02 09:31:16 +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.

Why 10s?

You should never have to wait longer than net.inet6.ip6.dad_count + 1 seconds.

Also the extra variable netwait_dad_timeout really isn't necessary in that case
if you use the sysctl.

/bz


>    MFC after:      1 week
>    Reviewed by:    olce
>    Differential Revision:  https://reviews.freebsd.org/D51889
> ---
> libexec/rc/rc.conf       |  2 ++
> libexec/rc/rc.d/netwait  | 84 ++++++++++++++++++++++++++++++++++--------------
> share/man/man5/rc.conf.5 | 24 +++++++++-----
> 3 files changed, 78 insertions(+), 32 deletions(-)
>
> diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf
> index c354aec44430..2589e2614c35 100644
> --- a/libexec/rc/rc.conf
> +++ b/libexec/rc/rc.conf
> @@ -500,6 +500,8 @@ 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="10"	# Total number of seconds to wait for DAD.
>
> ### 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..b609440a2e4e 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,36 @@ 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}" -ge 1 ]; then
> +		err 1 "netwait_if_timeout must be >= 1"
> +	fi
> +	if ! [ "${netwait_dad_timeout}" -ge 1 ]; then
> +		err 1 "netwait_dad_timeout must be >= 1"
> +	fi
> +	if ! [ "${netwait_timeout}" -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 +73,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 +123,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 +135,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..c0048f27c740 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 2, 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,18 @@ 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
> +Indicates the total number of seconds to wait for DAD to complete.
> +The default is 10.
> .It Va rctl_enable
> .Pq Vt bool
> If set to
>

-- 
Bjoern A. Zeeb                                                     r15:7
--0-768921551-1759595003=:11296--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?2r6r204q-qs32-70pq-rqn1-5s4p54r1385>