The branch main has been updated by markj:

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

commit df6861d755c8f72380ae7fb8df535b27eba8c0be
Author:     Mark Johnston <[email protected]>
AuthorDate: 2025-12-19 14:11:20 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2025-12-19 14:11:20 +0000

    ifconfig: Fix the -L flag when using netlink
    
    By default, when ifconfig shows a v6 address derived from a
    router-advertised prefix, it shows the initial preferred and valid
    lifetimes.  When -L is specified, it is supposed to show the remaining
    lifetimes, but this was broken in the conversion to netlink.
    
    Fix that, and add a regression test which validates ifconfig output
    before and after a short-lived address expires.
    
    Reported by:    Franco Fichtner <[email protected]>
    Reviewed by:    melifaro, allanjude, Seyed Pouria Mousavizadeh Tehrani
    Fixes:          4c91a5dfe483 ("ifconfig: make interface and address listing 
use Netlink as transport")
    MFC after:      2 weeks
    Sponsored by:   OPNsense
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D54294
---
 sbin/ifconfig/af_inet6.c  |  6 +++--
 tests/sys/netinet6/ndp.sh | 62 +++++++++++++++++++++++++++++++++++++++++++++++
 tests/sys/netinet6/ra.py  | 11 ++++++++-
 3 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index 9386f5eaf513..365f01be9590 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -375,8 +375,10 @@ show_lifetime(struct ifa_cacheinfo *ci)
        vl = (ci->ifa_valid == ND6_INFINITE_LIFETIME) ? 0 : ci->ifa_valid;
 
        clock_gettime(CLOCK_MONOTONIC_FAST, &now);
-       print_lifetime("pltime", pl + now.tv_sec, &now);
-       print_lifetime("vltime", vl + now.tv_sec, &now);
+       print_lifetime("pltime",
+           pl + (ip6lifetime ? ci->tstamp / 1000 : now.tv_sec), &now);
+       print_lifetime("vltime",
+           vl + (ip6lifetime ? ci->tstamp / 1000 : now.tv_sec), &now);
 }
 
 static void
diff --git a/tests/sys/netinet6/ndp.sh b/tests/sys/netinet6/ndp.sh
index 21a50cda02ba..3464ac59c898 100755
--- a/tests/sys/netinet6/ndp.sh
+++ b/tests/sys/netinet6/ndp.sh
@@ -226,10 +226,72 @@ ndp_prefix_len_mismatch_cleanup() {
        vnet_cleanup
 }
 
+atf_test_case "ndp_prefix_lifetime" "cleanup"
+ndp_prefix_lifetime_head() {
+       atf_set descr 'Test ndp slaac address lifetime handling'
+       atf_set require.user root
+       atf_set require.progs python3 scapy
+}
+
+ndp_prefix_lifetime_body() {
+       local epair0 jname prefix
+
+       vnet_init
+
+       jname="v6t-ndp_prefix_lifetime"
+
+       epair0=$(vnet_mkepair)
+
+       vnet_mkjail ${jname} ${epair0}a
+
+       ndp_if_up ${epair0}a ${jname}
+       ndp_if_up ${epair0}b
+       atf_check jexec ${jname} ifconfig ${epair0}a inet6 accept_rtadv no_dad
+
+       prefix="2001:db8:ffff:1000:"
+
+        # Send an RA advertising a prefix.
+       atf_check -e ignore python3 $(atf_get_srcdir)/ra.py \
+           --sendif ${epair0}b \
+           --dst $(ndp_if_lladdr ${epair0}a ${jname}) \
+           --src $(ndp_if_lladdr ${epair0}b) \
+           --prefix "2001:db8:ffff:1000::" --prefixlen 64 \
+           --validlifetime 10 --preferredlifetime 5
+
+       # Wait for a default router to appear.
+       while [ -z "$(jexec ${jname} ndp -r)" ]; do
+               sleep 0.1
+       done
+       atf_check \
+           -o match:"^default[[:space:]]+fe80:" \
+           jexec ${jname} netstat -rn -6
+
+       atf_check \
+           -o match:"inet6 ${prefix}.* prefixlen 64 autoconf pltime 5 vltime 
10" \
+           jexec ${jname} ifconfig ${epair0}a
+
+       # Wait for the address to become deprecated.
+       sleep 6
+       atf_check \
+           -o match:"inet6 ${prefix}.* prefixlen 64 deprecated autoconf pltime 
0 vltime [1-9]+" \
+           jexec ${jname} ifconfig -L ${epair0}a
+
+       # Wait for the address to expire.
+       sleep 6
+       atf_check \
+           -o not-match:"inet6 ${prefix}.*" \
+           jexec ${jname} ifconfig ${epair0}a
+}
+
+ndp_prefix_lifetime_cleanup() {
+       vnet_cleanup
+}
+
 atf_init_test_cases()
 {
        atf_add_test_case "ndp_add_gu_success"
        atf_add_test_case "ndp_del_gu_success"
        atf_add_test_case "ndp_slaac_default_route"
        atf_add_test_case "ndp_prefix_len_mismatch"
+       atf_add_test_case "ndp_prefix_lifetime"
 }
diff --git a/tests/sys/netinet6/ra.py b/tests/sys/netinet6/ra.py
index a5016b3f6e9b..1b08c3e53c05 100644
--- a/tests/sys/netinet6/ra.py
+++ b/tests/sys/netinet6/ra.py
@@ -25,12 +25,21 @@ def main():
                         help='The prefix to be advertised')
     parser.add_argument('--prefixlen', nargs=1, required=True, type=int,
                         help='The prefix length to be advertised')
+    parser.add_argument('--validlifetime', nargs=1, required=False,
+                        type=int, default=4294967295,
+                        help='The valid lifetime of the prefix')
+    parser.add_argument('--preferredlifetime', nargs=1, required=False,
+                        type=int, default=4294967295,
+                        help='The preferred lifetime of the prefix')
 
     args = parser.parse_args()
     pkt = sp.Ether() / \
         sp.IPv6(src=args.src, dst=args.dst) / \
         sp.ICMPv6ND_RA(chlim=64) / \
-        sp.ICMPv6NDOptPrefixInfo(prefix=args.prefix, prefixlen=args.prefixlen)
+        sp.ICMPv6NDOptPrefixInfo(prefix=args.prefix,
+                                 prefixlen=args.prefixlen,
+                                 validlifetime=args.validlifetime,
+                                 preferredlifetime=args.preferredlifetime)
 
     sp.sendp(pkt, iface=args.sendif[0], verbose=False)
     sys.exit(0)

Reply via email to