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 <franco@opnsense.org>
Reviewed by:	melifaro, allanjude, Seyed Pouria Mousavizadeh Tehrani
Fixes:		4c91a5dfe4 ("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
This commit is contained in:
Mark Johnston
2025-12-19 14:11:20 +00:00
parent 7080c1b09d
commit df6861d755
3 changed files with 76 additions and 3 deletions
+4 -2
View File
@@ -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
+62
View File
@@ -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"
}
+10 -1
View File
@@ -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)