When a dynamic prefix is delegated, dhcp6c use invalid pltime and vltime :
```
copyin_option: IA_PD prefix: 2001:xxx:xxxx:xxxx::/56 pltime=172800 vltime=259200
...
update_prefix: create a prefix 2001:xxx:xxxx:xxxx::/56 pltime=94613834736384, vltime=94613834822784
```
Thus it cannot renew the prefix (or even renew/rebind the lease) upon lease timeout.
This is the fix i'm using on the dhcp6c script to force updating pltime and vltime on delegated prefix ifaces (modified templates/dhcp-client/dhcp6c-script.j2) :
```
#!/usr/bin/env bash
# Update DNS information for DHCPv6 clients
# should be used only if vyos-hostsd is running
if /usr/bin/systemctl -q is-active vyos-hostsd; then
hostsd_client="/usr/bin/vyos-hostsd-client"
hostsd_changes=
if [ -n "$new_domain_name" ]; then
logmsg info "Deleting search domains with tag \"dhcpv6-{{ ifname }}\" via vyos-hostsd-client"
$hostsd_client --delete-search-domains --tag "dhcpv6-{{ ifname }}"
logmsg info "Adding domain name \"$new_domain_name\" as search domain with tag \"dhcpv6-{{ ifname }}\" via vyos-hostsd-client"
$hostsd_client --add-search-domains "$new_domain_name" --tag "dhcpv6-{{ ifname }}"
hostsd_changes=y
fi
if [ -n "$new_domain_name_servers" ]; then
logmsg info "Deleting nameservers with tag \"dhcpv6-{{ ifname }}\" via vyos-hostsd-client"
$hostsd_client --delete-name-servers --tag "dhcpv6-{{ ifname }}"
logmsg info "Adding nameservers \"$new_domain_name_servers\" with tag \"dhcpv6-{{ ifname }}\" via vyos-hostsd-client"
$hostsd_client --add-name-servers $new_domain_name_servers --tag "dhcpv6-{{ ifname }}"
hostsd_changes=y
fi
if [ $hostsd_changes ]; then
logmsg info "Applying changes via vyos-hostsd-client"
$hostsd_client --apply
else
logmsg info "No changes to apply via vyos-hostsd-client"
fi
fi
# VyOS dhcp6c hook (bash): reset on-link /64 lifetimes to lease pltime/vltime on every Reply
# - WAN inferred from script filename: dhcp6c.<wan>.script
# - LAN ifs (+optional ifid) parsed from /run/dhcp6c/dhcp6c.<wan>.conf
# - pltime/vltime parsed from journal (latest "IA_PD prefix" line)
# - Logs via systemd-cat; reloads radvd after updates
set -euo pipefail
LOG_TAG="dhcp6c-hook"
log() {
# usage: log <priority> <message...> (emerg|alert|crit|err|warning|notice|info|debug)
local pri="${1:-info}"; shift || true
systemd-cat -t "$LOG_TAG" -p "$pri" <<<"${*:-}"
}
# --- derive WAN from script filename: dhcp6c.<wan>.script
BN="$(basename "$0")"
WAN_IF=""
if [[ "$BN" =~ dhcp6c\.([^.]+)\.script$ ]]; then
WAN_IF="${BASH_REMATCH[1]}"
else
log warning "cannot infer WAN from $BN"; exit 0
fi
CONF="/run/dhcp6c/dhcp6c.${WAN_IF}.conf"
UNIT="dhcp6c@${WAN_IF}.service"
LOOKBACK="30min ago"
# --- pull latest IA_PD prefix & lifetimes from the journal
PLTIME=""; VLTIME=""; PD_ADDR=""; PD_PLEN=""
if J="$(journalctl -u "$UNIT" --since "$LOOKBACK" --no-pager 2>/dev/null || true)"; then
if L="$(grep -E 'IA_PD prefix:' <<<"$J" | tail -n1)"; then
[[ "$L" =~ pltime=([0-9]+) ]] && PLTIME="${BASH_REMATCH[1]}"
[[ "$L" =~ vltime=([0-9]+) ]] && VLTIME="${BASH_REMATCH[1]}"
if [[ "$L" =~ ([0-9a-fA-F:]+)\/([0-9]+) ]]; then
PD_ADDR="${BASH_REMATCH[1]}"
PD_PLEN="${BASH_REMATCH[2]}"
fi
fi
fi
if [[ -z "$PLTIME" || -z "$VLTIME" || -z "$PD_ADDR" ]]; then
log warning "missing pltime/vltime or PD from journal; skipping"
exit 0
fi
# Normalize PD prefix text (lowercase). We'll match by simple substring.
PD_TXT="${PD_ADDR,,}"
log info "PD ${PD_ADDR}/${PD_PLEN}, pltime=$PLTIME vltime=$VLTIME (matching by substring '${PD_TXT}')"
# --- collect only the interfaces managed by dhcp6c for PD (prefix-interface blocks)
if [[ ! -r "$CONF" ]]; then
log warning "cannot read $CONF; nothing to do"
exit 0
fi
# Extract "prefix-interface <if>" names; de-duplicate
mapfile -t LAN_IFS < <(awk '
/^ *prefix-interface[ \t]+[A-Za-z0-9_.:-]+[ \t]*\{/ {
match($0,/prefix-interface[ \t]+([A-Za-z0-9_.:-]+)/,m);
if (m[1]!="") print m[1];
}
' "$CONF" | awk '!seen[$0]++')
if ((${#LAN_IFS[@]}==0)); then
log info "no prefix-interface entries found in $CONF; nothing to do"
exit 0
fi
changed=0
# --- for each declared LAN interface, reset lifetimes on any address containing the PD text
for ifc in "${LAN_IFS[@]}"; do
# Skip WAN interface if it was also listed (unlikely)
[[ "$ifc" == "$WAN_IF" ]] && continue
# Iterate global IPv6 addresses on the iface
while read -r _idx _dev fam a_pfx _rest; do
[[ "$fam" != "inet6" ]] && continue
addr="${a_pfx%%/*}"
# textual substring match (lowercased)
if [[ "${addr,,}" == *"${PD_TXT}"* ]]; then
log info "resetting ${a_pfx} on ${ifc} to pref=$PLTIME valid=$VLTIME"
if ip -6 addr change "$a_pfx" dev "$ifc" preferred_lft "$PLTIME" valid_lft "$VLTIME"; then
changed=1
else
log warning "failed to change ${a_pfx} on ${ifc}"
fi
fi
done < <(ip -6 -o addr show dev "$ifc" scope global 2>/dev/null | awk '{print $1,$2,$3,$4}')
done
# --- re-announce via radvd if anything changed
if (( changed )); then
if systemctl reload radvd 2>/dev/null || systemctl restart radvd 2>/dev/null; then
log info "radvd reloaded after lifetime refresh"
else
log warning "failed to reload/restart radvd"
fi
else
log info "no addresses matched PD on configured interfaces; nothing updated"
fi
exit 0
```