From 16e4b05653643e7981c471269a6ddc0025e1b249 Mon Sep 17 00:00:00 2001
From: Daniel Barlow <dan@telent.net>
Date: Tue, 13 Feb 2024 12:57:41 +0000
Subject: [PATCH] dhcp6c: set preferred and valid address lifetimes

also workaround a bug in rebinding/updates where we get an error
from "ip addr add" trying to add an address that's already present
---
 modules/dhcp6c/acquire-delegated-prefix.fnl | 11 ++++++++++-
 modules/dhcp6c/acquire-wan-address.fnl      |  7 ++++++-
 pkgs/odhcp-script/odhcp6-script.fnl         |  6 +++++-
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/modules/dhcp6c/acquire-delegated-prefix.fnl b/modules/dhcp6c/acquire-delegated-prefix.fnl
index 07ff7afa..d785126c 100644
--- a/modules/dhcp6c/acquire-delegated-prefix.fnl
+++ b/modules/dhcp6c/acquire-delegated-prefix.fnl
@@ -14,9 +14,18 @@
 
 (fn update-prefixes [device prefixes new-prefixes]
   (let [(added deleted) (changes prefixes new-prefixes)]
+    ;; if some address has changed (e.g. preferred/valid lifetime)
+    ;; then we don't want to delete it before re-adding it because
+    ;; the kernel will drop any routes that go through it. On the
+    ;; other hand, we can't add it _before_ deleting it as we'll
+    ;; get an error that it already exists. Therefore, use "change"
+    ;; instead of "add", it works a bit more like an upsert
     (each [_ p (ipairs added)]
       (system
-       (.. "ip address add " p.address "1/" p.len " dev " device)))
+       (.. "ip address change " p.address "1/" p.len " dev " device
+           " valid_lft " p.valid
+           " preferred_lft " p.preferred
+           )))
     (each [_ p (ipairs deleted)]
       (system
        (.. "ip address del " p.address "1/" p.len " dev " device)))))
diff --git a/modules/dhcp6c/acquire-wan-address.fnl b/modules/dhcp6c/acquire-wan-address.fnl
index af6f92b0..38847bcd 100644
--- a/modules/dhcp6c/acquire-wan-address.fnl
+++ b/modules/dhcp6c/acquire-wan-address.fnl
@@ -17,9 +17,14 @@
 
 (fn update-addresses [wan-device addresses new-addresses]
   (let [(added deleted) (changes addresses new-addresses)]
+    ;; see comment in acquire-delegated-prefix.fnl
     (each [_ p (ipairs added)]
       (system
-       (.. "ip address add " p.address "/" p.len " dev " wan-device)))
+       (.. "ip address change " p.address "/" p.len
+           " dev " wan-device
+           " valid_lft " p.valid
+           " preferred_lft " p.preferred
+           )))
     (each [_ p (ipairs deleted)]
       (system
        (.. "ip address del " p.address "/" p.len " dev " wan-device)))
diff --git a/pkgs/odhcp-script/odhcp6-script.fnl b/pkgs/odhcp-script/odhcp6-script.fnl
index 0d166507..699f6951 100644
--- a/pkgs/odhcp-script/odhcp6-script.fnl
+++ b/pkgs/odhcp-script/odhcp6-script.fnl
@@ -20,7 +20,11 @@
       out))
   (let [(address len preferred valid extra)
         (string.match str "(.-)/(%d+),(%d+),(%d+)(.*)$")]
-    (merge {: address : len : preferred : valid} (parse-extra extra))))
+    (merge {: address : len
+            :preferred (or preferred "forever")
+            :valid (or valid "forever")
+            }
+           (parse-extra extra))))
 
 (fn write-addresses [prefix addresses]
   (each [_ a (ipairs (split " " addresses))]