]> Cypherpunks repositories - dsc.git/commitdiff
netreconf
authorSergey Matveev <stargrave@stargrave.org>
Thu, 18 Sep 2025 08:15:58 +0000 (11:15 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Wed, 24 Sep 2025 11:49:34 +0000 (14:49 +0300)
netreconf [new file with mode: 0755]

diff --git a/netreconf b/netreconf
new file mode 100755 (executable)
index 0000000..f10ae23
--- /dev/null
+++ b/netreconf
@@ -0,0 +1,70 @@
+#!/usr/bin/env tclsh
+# Generate network reconfiguration commands, based on dsc's net/
+# configuration and current interfaces state.
+# Copyright (C) 2025 Sergey Matveev <stargrave@stargrave.org>
+#
+# That script calls dsc command, so do not forget proper $DSC_STASH value.
+# It outputs ip-* commands to stdout, intending you to feed to the shell.
+
+proc list-addrs {iface} {
+    set addrs [list]
+    catch {exec ip addr list dev $iface} lines
+    foreach l [split $lines \n] {
+        if {[regexp {inet (\S+)} $l _ addr]} {
+            lappend addrs $addr
+        }
+        if {[regexp {inet6 (\S+)} $l _ addr] && [string range $addr 0 4] != "fe80:"} {
+            lappend addrs $addr
+        }
+    }
+    return $addrs
+}
+
+# Get list of non-loopback system interfaces
+set sysIfaces [list]
+foreach l [split [exec ip link] \n] {
+    if {[regexp {^\d+: (\w+): } $l _ iface] && $iface != "lo"} {
+        lappend sysIfaces $iface
+    }
+}
+
+set dscIfaces [split [exec dsc get net/*] \n]
+
+foreach iface $sysIfaces {
+    if {[lsearch -exact $dscIfaces $iface] == -1} {
+        # If interface is not mentioned in dsc, then disable it and remove
+        # all addresses, as they are still known to the system
+        puts "ip link set $iface down"
+        foreach addr [list-addrs $iface] {
+            puts "ip addr del $addr dev $iface"
+        }
+    } else {
+        set mtu [exec dsc get net/$iface/mtu]
+        puts "ip link set $iface mtu $mtu"
+        puts "ip link set $iface up"
+    }
+}
+
+foreach iface $dscIfaces {
+    if {[lsearch -exact $sysIfaces $iface] == -1} {
+        # If dsc's interface is not present in the system, skip it
+        continue
+    }
+    set dscAddrs [list]
+    foreach addr [split [exec dsc get net/$iface/addr/*] \n] {
+        set prefixlen [exec dsc get net/$iface/addr/$addr/prefixlen]
+        lappend dscAddrs $addr/$prefixlen
+    }
+    foreach addr [list-addrs $iface] {
+        set idx [lsearch -exact $dscAddrs $addr]
+        if {$idx == -1} {
+            puts "ip addr del $addr dev $iface"
+        } else {
+            # Address is already present
+            set $dscAddrs [lreplace $dscAddrs $idx $idx]
+        }
+    }
+    foreach addr $dscAddrs {
+        puts "ip addr add $addr dev $iface"
+    }
+}