liminix

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 40194d53517fad36b387e7ce197a365f7582fec9
parent ff7aaec874b53383008666c064f1efa8dfb29733
Author: Daniel Barlow <dan@telent.net>
Date:   Tue, 11 Nov 2025 21:00:16 +0000

enable ipv6 autoconfig when dhcp6c is specified

DHCP6 and autoconfig work in tandem not in opposition! dhcp6 does not
provide a default gateway: it depends on router solicitation/router
adverts for that

Tl;dr the network/site admin will ensure that router adverts are being
sent periodically. The adverts will have either Autonomous or Managed
bits set and that is what tells the host to use SLAAC or to use DHCP6

Diffstat:
Mmodules/dhcp6c/client.nix | 34++++++++++++++++++++--------------
Mmodules/dhcp6c/default.nix | 3+++
Amodules/ipv6-autoconfig/autoconfig.nix | 37+++++++++++++++++++++++++++++++++++++
Amodules/ipv6-autoconfig/default.nix | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 111 insertions(+), 14 deletions(-)

diff --git a/modules/dhcp6c/client.nix b/modules/dhcp6c/client.nix @@ -2,26 +2,32 @@ liminix, odhcp6c, odhcp-script, - svc + svc, }: { interface }: let inherit (liminix.services) longrun; inherit (liminix) outputRef; name = "dhcp6c.${interface.name}"; - service = - longrun { - inherit name; - notification-fd = 10; - run = '' - export SERVICE_STATE=$SERVICE_OUTPUTS/${name} - ifname=$(output ${interface} ifname) - test -n "$ifname" && ${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $ifname - ) - ''; - dependencies = [ interface ]; - }; -in svc.secrets.subscriber.build { + autoconf = svc.ipv6.autoconfig.build { + inherit interface; + }; + service = longrun { + inherit name; + notification-fd = 10; + run = '' + export SERVICE_STATE=$SERVICE_OUTPUTS/${name} + ifname=$(output ${interface} ifname) + test -n "$ifname" && ${odhcp6c}/bin/odhcp6c -s ${odhcp-script} -e -v -p /run/${name}.pid -P0 $ifname + ) + ''; + dependencies = [ + interface + autoconf + ]; + }; +in +svc.secrets.subscriber.build { # if the ppp service gets restarted, the interface may be different and # we will have to restart dhcp on the new one watch = [ (outputRef interface "ifindex") ]; diff --git a/modules/dhcp6c/default.nix b/modules/dhcp6c/default.nix @@ -20,6 +20,9 @@ let inherit (pkgs) liminix; in { + imports = [ + ../ipv6-autoconfig + ]; options = { system.service.dhcp6c = { client = mkOption { type = liminix.lib.types.serviceDefn; }; diff --git a/modules/ipv6-autoconfig/autoconfig.nix b/modules/ipv6-autoconfig/autoconfig.nix @@ -0,0 +1,37 @@ +{ + liminix, + writeAshScript, + serviceFns, + lib, +}: +{ + interface, + role, + sysctl, +}: +let + inherit (liminix.services) oneshot; + inherit (lib) recursiveUpdate; + name = "${interface.name}.autoconfig"; + sysctls = + let + s = recursiveUpdate { + autoconf = "1"; + accept_ra = (role == "host"); + } sysctl; + in + liminix.writeSysctls s; +in +oneshot { + inherit name; + dependencies = [ interface ]; + up = '' + cd /proc/sys/net/ipv6/conf/$(output ${interface} ifname) + ${sysctls} + ''; + down = '' + cd /proc/sys/net/ipv6/conf/$(output ${interface} ifname) + echo "0" > autoconf + echo "0" > accept_ra + ''; +} diff --git a/modules/ipv6-autoconfig/default.nix b/modules/ipv6-autoconfig/default.nix @@ -0,0 +1,51 @@ +## IPv6 Autoconfiguration +## ====================== +## +## Enable IPv6 neighbour discovery for an interface and allow it +## to participate in router solicitation/router advertisement. +## +## You need this if you want to get an IPv6 address (or addresses) +## whether by stateless allocation (SLAAC) or by DHCP6. You don't +## need this on interfaces that are members of bridges, because they +## shouldn't have addresses of their own. + +{ + lib, + pkgs, + config, + ... +}: +let + inherit (lib) mkOption types; + inherit (pkgs) liminix; +in +{ + options.system.service.ipv6.autoconfig = mkOption { + type = liminix.lib.types.serviceDefn; + }; + + config.system.service.ipv6 = { + autoconfig = config.system.callService ./autoconfig.nix { + interface = mkOption { + type = liminix.lib.types.interface; + }; + role = mkOption { + description = "configure as host or router (controls whether accept_ra sis set)"; + type = types.enum [ + "host" + "router" + ]; + default = "host"; + }; + sysctl = mkOption { + type = types.attrsOf types.str; + description = "additional sysctl settings to apply to /proc/sys/net/ipv6/conf/<ifname>"; + default = { }; + example = { + dad_transmits = 1; + hop_limit = 64; + }; + }; + }; + }; +}