Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 12 Jan 2026 15:34:51 +0000
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 74999aac5eff - main - in6: Modify address prefix lifetimes when updating address lifetimes
Message-ID:  <6965149b.260a1.5e50358b@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=74999aac5effb9b32d12f413ef51e87b15c8a0d8

commit 74999aac5effb9b32d12f413ef51e87b15c8a0d8
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-01-12 13:49:54 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-01-12 15:34:43 +0000

    in6: Modify address prefix lifetimes when updating address lifetimes
    
    When one uses SIOCAIFADDR_IN6 to add a v6 address, it's possible to set
    the preferred and valid lifetimes of the address.  If the address
    already exists, this ioctl will recalculate and update the expiry times
    based on the provided timestamps.
    
    When adding a new address, the lifetimes are inherited by the prefix as
    well, but only if we create a new prefix.  If the prefix already exists,
    as it will in the case where an address is being updated rather than
    being added, we do not touch the prefix lifetimes at all.  This means
    that the original address lifetime still applies to the route associated
    with that prefix, so when the prefix expires, the route goes away.
    
    This behaviour doesn't make a lot of sense: if the admin updates an
    address lifetime, we should ensure that the prefix lifetime is updated
    too.  Make that change, ensuring that we do not shorten the prefix
    lifetime, as the prefix might be shared among multiple interface
    addresses.
    
    Add a regression test.
    
    Co-authored by: Franco Fichtner <franco@opnsense.org>
    Reviewed by:    pouria, zlei, ae
    MFC after:      2 weeks
    Sponsored by:   OPNsense
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D54562
---
 sys/netinet6/in6.c        | 22 ++++++++++++++
 tests/sys/netinet6/ndp.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 98 insertions(+)

diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index bdf19c876519..e8b76bdd579b 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1330,6 +1330,28 @@ in6_addifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra, struct in6_ifaddr *i
 				(*carp_detach_p)(&ia->ia_ifa, false);
 			goto out;
 		}
+	} else if (pr->ndpr_raf_onlink) {
+		time_t expiry;
+
+		/*
+		 * If the prefix already exists, update lifetimes, but avoid
+		 * shortening them.
+		 */
+		ND6_WLOCK();
+		expiry = in6_expire_time(pr0.ndpr_pltime);
+		if (pr->ndpr_preferred != 0 &&
+		    (pr->ndpr_preferred < expiry || expiry == 0)) {
+			pr->ndpr_pltime = pr0.ndpr_pltime;
+			pr->ndpr_preferred = expiry;
+		}
+		expiry = in6_expire_time(pr0.ndpr_vltime);
+		if (pr->ndpr_expire != 0 &&
+		    (pr->ndpr_expire < expiry || expiry == 0)) {
+			pr->ndpr_vltime = pr0.ndpr_vltime;
+			pr->ndpr_expire = expiry;
+		}
+		pr->ndpr_lastupdate = time_uptime;
+		ND6_WUNLOCK();
 	}
 
 	/* relate the address to the prefix */
diff --git a/tests/sys/netinet6/ndp.sh b/tests/sys/netinet6/ndp.sh
index 3464ac59c898..8a16316740be 100755
--- a/tests/sys/netinet6/ndp.sh
+++ b/tests/sys/netinet6/ndp.sh
@@ -287,6 +287,81 @@ ndp_prefix_lifetime_cleanup() {
 	vnet_cleanup
 }
 
+atf_test_case "ndp_prefix_lifetime_extend"
+ndp_prefix_lifetime_extend_head() {
+	atf_set descr 'Test prefix lifetime updates via ifconfig'
+	atf_set require.user root
+	atf_set require.progs jq
+}
+
+get_prefix_attr() {
+	local prefix=$1
+	local attr=$2
+
+	ndp -p --libxo json | \
+	    jq -r '.ndp.["prefix-list"][] |
+	           select(.prefix == "'${prefix}'") | .["'${attr}'"]'
+}
+
+# Given a prefix, return its expiry time in seconds.
+prefix_expiry() {
+	get_prefix_attr $1 "expires_sec"
+}
+
+# Given a prefix, return its valid and preferred lifetimes.
+prefix_lifetimes() {
+	local p v
+
+	v=$(get_prefix_attr $1 "valid-lifetime")
+	p=$(get_prefix_attr $1 "preferred-lifetime")
+	echo $v $p
+}
+
+ndp_prefix_lifetime_extend_body() {
+	local epair ex1 ex2 ex3 prefix pltime vltime
+
+	atf_check -o save:epair ifconfig epair create
+	epair=$(cat epair)
+	atf_check ifconfig ${epair} up
+
+	prefix="2001:db8:ffff:1000::"
+
+	atf_check ifconfig ${epair} inet6 ${prefix}1/64 pltime 5 vltime 10
+	t=$(prefix_lifetimes ${prefix}/64)
+	if [ "${t}" != "10 5" ]; then
+		atf_fail "Unexpected lifetimes: ${t}"
+	fi
+	ex1=$(prefix_expiry ${prefix}/64)
+	if [ "${ex1}" -gt 10 ]; then
+		atf_fail "Unexpected expiry time: ${ex1}"
+	fi
+
+	# Double the address lifetime and verify that the prefix is
+	# updated.
+	atf_check ifconfig ${epair} inet6 ${prefix}1/64 pltime 10 vltime 20
+	t=$(prefix_lifetimes ${prefix}/64)
+	if [ "${t}" != "20 10" ]; then
+		atf_fail "Unexpected lifetimes: ${t}"
+	fi
+	ex2=$(prefix_expiry ${prefix}/64)
+	if [ "${ex2}" -le "${ex1}" ]; then
+		atf_fail "Expiry time was not extended: ${ex1} <= ${ex2}"
+	fi
+
+	# Add a second address from the same prefix with a shorter
+	# lifetime, and make sure that the prefix lifetime is not
+	# shortened.
+	atf_check ifconfig ${epair} inet6 ${prefix}2/64 pltime 5 vltime 10
+	t=$(prefix_lifetimes ${prefix}/64)
+	if [ "${t}" != "20 10" ]; then
+		atf_fail "Unexpected lifetimes: ${t}"
+	fi
+	ex3=$(prefix_expiry ${prefix}/64)
+	if [ "${ex3}" -lt "${ex2}" ]; then
+		atf_fail "Expiry time was shortened: ${ex2} <= ${ex3}"
+	fi
+}
+
 atf_init_test_cases()
 {
 	atf_add_test_case "ndp_add_gu_success"
@@ -294,4 +369,5 @@ atf_init_test_cases()
 	atf_add_test_case "ndp_slaac_default_route"
 	atf_add_test_case "ndp_prefix_len_mismatch"
 	atf_add_test_case "ndp_prefix_lifetime"
+	atf_add_test_case "ndp_prefix_lifetime_extend"
 }


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6965149b.260a1.5e50358b>