liminix

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

THOUGHTS.txt (260294B)


      1 Thu Sep 22 00:12:42 BST 2022
      2 
      3 Making quite reasonable progress, though only running under emulation.
      4 Since almost everything so far has been a recap of nixwrt, that's to
      5 be expected.
      6 
      7 The example config starts some services at boot, or at least attempts
      8 to. Next we shoud
      9 
     10  - add some network config to run-qemu
     11  - implement udhcp and odhcp properly to write outputs
     12   and create resolv.conf and all that
     13  - write some kind of test so we can refactor the crap
     14  - not let the tests write random junk everywhere
     15 
     16 Thu Sep 22 12:46:36 BST 2022
     17 
     18 We can store outputs in the s6 scan directory, it seems:
     19 
     20 > There is, however, a guarantee that s6-supervise will never touch subdirectories named data or env. So if you need to store user information in the service directory with the guarantee that it will never be mistaken for a configuration file, no matter the version of s6, you should store that information in the data or env subdirectories of the service directory.
     21 
     22 https://skarnet.org/software/s6/servicedir.html
     23 
     24 > process 'store/pj0b27l5728cypa5mmagz0q8ibzpik0h-execline-mips-unknown-linux-musl-2.9.0.1-bin/bin/execlineb' started with executable stack
     25 
     26 https://skarnet.org/lists/skaware/1550.html
     27 
     28 
     29 Thu Sep 22 16:14:49 BST 2022
     30 
     31 what network peers do we want to model for testing?
     32 
     33 - wan: pppoe
     34 - wan: ip over ethernet, w/ dhcp service provided
     35 - wan: l2tp over (ip over ethernet, w/ dhcp service provided)
     36 - lan: something with a dhcp client
     37 
     38 https://accel-ppp.readthedocs.io/en/latest/ could use this for testing
     39 pppoe and l2tp?
     40 
     41 
     42 Thu Sep 22 22:57:47 BST 2022
     43 
     44 To build a nixos vm with accel-ppp installed (not yet configured)
     45 
     46   nix-build '<nixpkgs/nixos>' -A vm -I nixos-config=./tests/ppp-server-configuration.nix -o ppp-server
     47   QEMU_OPTS="-display none -serial mon:stdio -nographic" ./ppp-server/bin/run-nixos-vm
     48 
     49 To test it's configured I thought I'd run it against an OpenWrt qemu
     50 install, so, fun with qemu networking ensues. This config in ../openwrt-qemu
     51 is using two multicast socket networks -
     52 
     53 nix-shell -p qemu --run "./run.sh ./openwrt-22.03.0-x86-64-generic-kernel.bin openwrt-22.03.0-x86-64-generic-ext4-rootfs.img "
     54 
     55 so hopefully we can spin up other VMs connected either to its lan or
     56 its wan: *however* we do first need to configure its wan to use pppoe
     57 
     58 uci set network.wan=interface
     59 uci set network.wan.device='eth1'
     60 uci set network.wan.proto='pppoe'
     61 uci set network.wan.username='db123@a.1'
     62 uci set network.wan.password='NotReallyTheSecret'
     63 
     64 (it's ext4 so this will probably stick)
     65 
     66 
     67 Fri Sep 23 10:27:22 BST 2022
     68 
     69 * mcast=230.0.0.1:1234  : access (interconnect between router and isp)
     70 * mcast=230.0.0.1:1235  : lan
     71 * mcast=230.0.0.1:1236  : world (the internet)
     72 
     73 
     74 Sun Sep 25 20:56:28 BST 2022
     75 
     76 TODO - bugs, missing bits, other infelicities as they occur to me:
     77 
     78 DONE 1) shutdown doesn't work as its using the busybox one not s6.
     79 
     80 2) perhaps we shouldn't have process-based services like dhcp, ppp
     81 implement "address provider interface" - instead have a separate
     82 service for interface address that depends on the service and uses its
     83 output
     84 
     85 * ppp is not like dhcp because dhcp finds addresses for an existing
     86   interface but ppp makes a new one
     87 
     88 3) when I killed ppp it restarted, but I don't think it reran
     89 defaultroute which is supposed to depend on it. (Might be important
     90 e.g. if we'd been assigned a different IP address). Investigate
     91 semantics of s6-rc service dependencies
     92 
     93 DONE 4) make the pppoe test run unattended
     94 
     95 5) write a test for udhcp
     96 
     97 6) squashfs size is ~ 14MB for a configuration with not much in it,
     98 look for obvious wastes of space
     99 
    100 7) some of the pppoe config should be moved into a ppp service
    101 
    102 8) some of configuration.nix (e.g. defining routes) should be moved into
    103 tools
    104 
    105 DONE 9) split tools up instead of having it all one file
    106 
    107 10) is it OK to depend on squashfs pseudofiles if we might want to
    108 switch to ubifs? will there always be a squashfs underneath? might
    109 we want to change the pseudofiles in an overlay?
    110 
    111 11) haven't done (overlayfs) overlays at all
    112 
    113 12) overlay.nix needs splitting up
    114 
    115 13) upgrade ppp to something with an ipv6-up-script option
    116 
    117 14) add ipv6 support generally
    118 
    119 15) "ip address add" seems to magically recognise v4 vs v6 but
    120 is that specified or fluke?
    121 
    122 16) tighten up the module specs. (DONE) services.foo should be a s6-rc
    123 service, (DONE) kernel config should be checked in some way
    124 
    125 DONE 17) rename nixwrt references in kernel builder
    126 
    127 18) maybe stop suffixing all the service names with .service
    128 
    129 19) syslogd - use busybox or s6?
    130 
    131 chat -s -S ogin:--ogin: root / "ip address show dev ppp0 | grep ppp0" 192.168.100.1  "/nix/store/*-s6-linux-init-*/bin/s6-linux-init-hpr -p"
    132 
    133 
    134 Working towards a general goal of having a derivation we can
    135 usefully run `nix path-info` on - or some other tool that will
    136 tell us what's making the images big. The squashfs doesn't
    137 have this information.
    138 
    139 Towards that end (really? can't remember how ...) what would be a
    140 way for packages to declare "I want to add files to /etc"? Is that
    141 even a good idea?
    142 
    143 Thinking we should turn s6-init-files back into a real derivation.
    144 
    145 Tue Sep 27 00:31:45 BST 2022
    146 
    147 > Thinking we should turn s6-init-files back into a real derivation.
    148 
    149 This turns out to be Not That Simple, because it contains weird shit
    150 (sticky bits and fifos).
    151 
    152 Tue Sep 27 09:50:44 BST 2022
    153 
    154 * allow modules to register activation scripts that are run on the
    155 root filesystem once all packages are installed
    156 
    157   - do they run on build or on host? if we're upgrading in place
    158   how do we ship filesystem changes to the host?
    159 
    160 or:
    161 
    162 * allow modules to declare environment.*, use pseudofile on build and
    163 create real files on host. will need to keep the implementation on
    164   host faily simple because restricted environment
    165 
    166 Tue Sep 27 16:14:18 BST 2022
    167 
    168 TODO list is getting both longer and shorter, though longer on
    169 average.
    170 
    171 2) perhaps we shouldn't use process-based services like [ou]dhcp as
    172 queryable endpoint for interface addresses (e.g. when adding routes).
    173 Instead have a separate service for interface address that depends on
    174 the *dhcp and uses its output
    175 
    176 3) when I killed ppp it restarted, but I don't think it reran
    177 defaultroute which is supposed to depend on it. (Might be important
    178 e.g. if we'd been assigned a different IP address). Investigate
    179 semantics of s6-rc service dependencies
    180 
    181 4) figure out a nice way to fit ppp into this model as it actually
    182 creates the interface instead of using an existing unconfigured one
    183 
    184 5) write a test for udhcp
    185 
    186 7) some of the pppoe config should be moved into a ppp service
    187 
    188 11) haven't done (overlayfs) overlays at all
    189 
    190 13) upgrade ppp to something with an ipv6-up-script option, move ppp and pppoe derivations into their own files
    191 
    192 14) add ipv6 support generally
    193 
    194 15) "ip address add" seems to magically recognise v4 vs v6 but
    195 is that specified or fluke?
    196 
    197 19) ship logs somehow to log collection system
    198 
    199 21) dhcp, dns, hostap service for lan
    200 
    201 22) support real hardware
    202 
    203 Tue Sep 27 22:00:36 BST 2022
    204 
    205 Found the cause of huge image size: rp-pppoe ships with scripts that
    206 reference build-time packages, so we have x86-64 glibc in there
    207 
    208 We don't need syslog just to accommodate ppp, there's an underdocumented
    209 option for it to log to a file descriptor
    210 
    211 Wed Sep 28 16:04:02 BST 2022
    212 
    213 Based on https://unix.stackexchange.com/a/431953 if we can forge
    214 ethernet packets we might be able to write tests for e.g. "is the vm
    215 running a dhcp server"
    216 
    217 Wed Sep 28 21:29:05 BST 2022
    218 
    219 We can use Python "scapy" to generate dhcp request packets, and Python
    220 'socket' model to send them encapsulated in UDP. Win
    221 
    222 It's extremely janky python
    223 
    224 Thu Sep 29 15:24:37 BST 2022
    225 
    226 Two points to ponder
    227 
    228 1) where service config depends on outputs of other services, we
    229 do that rather ugly "$(cat ${output ....})" construct. Can we improve on
    230 that? Maybe we could have some kind of tooling to read them as environment
    231 variables ...
    232 
    233 2) we have given no consideration yet to secrets. we want the secrets to
    234 be not in the store; we want some way of refreshing them when they change
    235 
    236 Sat Oct  1 14:24:21 BST 2022
    237 
    238 The MAC80211_HWSIM kernel config creates virtual wlan[01] devices
    239 which hostapd will work with, and a hwsim0 which we can use to monitor
    240 (though not inject) trafic. Could we use this for wifi tests? How do
    241 we make the guest hwsim0 visible to the host?
    242 
    243 
    244 Sat Oct  1 18:41:31 BST 2022
    245 
    246 virtual serial ports: I struggled with qemu for ages to get this to work.
    247 You also need the unhelpfully named CONFIG_VIRTIO_CONSOLE option in
    248 kconfig
    249 
    250 QEMU_OPTIONS="-nodefaults  -chardev socket,path=/tmp/wlan,server=on,wait=off,id=wlan  -device virtio-serial-pci -device virtserialport,name=wlan,chardev=wlan"
    251 
    252 Sun Oct  2 09:34:48 BST 2022
    253 
    254 We could implement the secrets store as a service, then the secrets
    255 are outputs.
    256 
    257 Things we can do in qemu
    258 
    259 1) make interface address service that depends on dhcp, instead of
    260   being set by it directly
    261 2) check out restart behaviour of dependent services when depended-on
    262   service dies
    263 3) pppd _creates_ an interface, work out how to fit it into this model
    264 5) add bridge support for lan
    265 8) upgrade ppp to something with an ipv6-up-script option, move ppp and pppoe derivations into their own files
    266 9) get ipv6 address from pppoe
    267 10) get ipv6 delegation from pppoe and add prefix to lan
    268 11) support dhcp6 in dnsmasq, and advertise prefix on lan
    269 12) firewalling and nat
    270  - default deny or zero trust?
    271 14) write secrets holder as a service with outputs
    272 20) should we check that references to outputs actually correspond with
    273   those provided by a service
    274 
    275 Things we probably do on hardware
    276 
    277 6) writable filesystem (ubifs?)
    278 7) overlay with squashfs/ubifs - useful? think about workflows for
    279 how this thing is installed
    280 16) gl-ar750
    281 17) mediatek device - gl-mt300 or whatever I have lying around
    282 18) some kind of arm (banana pi router?)
    283 19) should we give routeros a hardware ethernet and maybe an l2tp upstream,
    284  then we could dogfood the hardware devices.  we could run an l2tp service
    285  at mythic-beasts, got a /48 there
    286 
    287 
    288 
    289 https://skarnet.org/software/s6/s6-fghack.html looks like a handy thing
    290 we hope we'll never have to use
    291 
    292 Sun Oct  2 22:22:17 BST 2022
    293 
    294 > make interface address service that depends on dhcp, instead of being set by it directly
    295 
    296 We can do this for dhcp, but we can't do it for ppp. Running the ppp service
    297 creates a ppp[012n] interface and assigns it an ipv4 address and there's not
    298 a whole lot we can easily do to unbundle that.
    299 
    300 So
    301 
    302 - the ppp service needs to behave as if it were a "link" service
    303 - either it *also* needs to behave as an address service, or we could
    304   have an address service that subscribes to it and does nothing other than
    305   translate output formats
    306 
    307 Note regarding that second bullet: at the moment the static address
    308 service has no outputs anyway!
    309 
    310 
    311 Tue Oct  4 22:43:02 BST 2022
    312 
    313 While trying to make the TFTP workflow not awful I seem to have written
    314 a TFTP server.
    315 
    316 
    317 Thu Oct  6 19:26:40 BST 2022
    318 
    319 We have a booting kernel on gl-ar750, but we aren't at a point that it can
    320 find a root filesystem
    321 
    322 I'd *like* to be able to use the same delivery mechanism (kernel uimage
    323 concatenated monolithic
    324 
    325 
    326 Sat Oct  8 11:12:09 BST 2022
    327 
    328 We have it booting on hardware, mounting root fs, running getty :-)
    329 
    330 For NixWRT TFTP boots we used a single image with both kernel and squashfs, and
    331 relied on CONFIG_MTD_SPLIT_FIRMWARE to identify where the boundary was and create
    332 /dev/mdtn devices at the right offsets so that the kernel could find the
    333 squashfs
    334 
    335 For Liminix we're not going to do that.
    336 
    337 * CONFIG_MTD_SPLIT_FIRMWARE is only available in OpenWrt patches
    338 * it's an uncomfortable level of automagic just to save us doing two TFTPs
    339   instea of one
    340 * the generated image is anyway not the one we'd write to flash (has unneeded
    341    PHRAM support)
    342 * it means we need to memmap out enough ram for the whole image inc kernel when really
    343   all we need to reserve is the rootfs bit
    344 
    345 
    346 Sat Oct  8 11:23:08 BST 2022
    347 
    348 "halt" and "reboot" don't work on gl-ar750
    349 
    350 Sat Oct  8 13:10:00 BST 2022
    351 
    352 Where do we go with this ar750?
    353 
    354 - wired networking
    355 - wifi
    356 
    357 
    358 Sun Oct  9 09:57:35 BST 2022
    359 
    360 We want to be able to package kernel modules as regular derivations, so that
    361 they get added to the filesystem
    362 
    363 This means they need access to kernel.modulesupport
    364 
    365 This means  kernel.modulesupport needs to be in pkgs too?
    366 
    367 This is fine, probably, but we'd like to avoid closing over vmlinux because
    368 there's no need for it to be in the filesystem
    369 
    370 Mon Oct 10 22:57:23 BST 2022
    371 
    372 The problem is that kernel kconfig options are manipulated in the
    373 liminix modules, which means that data must be (transitively) available
    374 to modules, so they can't be regular packages as they're tied so tightly
    375 to the exact config. Unless we define a second overlay that references
    376 the configuration object, but my head hurts when I start to think about that
    377 so maybe not.
    378 
    379 Tue Oct 11 00:00:13 BST 2022
    380 
    381 Building ag71xx (ethernet driver) as a module doesn't work because
    382 it references a symbol ath79_pll_base in the kernel that hasn't been
    383 marked with EXPORT_SYMBOL.
    384 
    385 We could forge an object file that "declares" it with a gross and disgusting hack like this
    386 
    387 $ echo > empty # not actually "empty", objcopy complains about that
    388 $ grep ath79_pll_base /nix/store/jcc114cd13xa8aa4mil35rlnmxnlmv09-vmlinux-mips-unknown-linux-musl-modulesupport/System.map
    389 ffffffff807b2094 B ath79_pll_base
    390 $ mips-unknown-linux-musl-objcopy   -I binary -O elf32-big --add-section .bss=empty  --add-symbol ath79_pll_base=.bss:0x807b2094  empty f.o
    391 
    392 I don't claim this is a good idea, just an idea. Thought was that we would not
    393 have to declare its type this way. Also it might not work with kaslr
    394 https://stackoverflow.com/a/68903503
    395 
    396 
    397 Backstory: why are we trying to build this as a module? because the
    398 openwrt fork of it seems to be a bit more advanced than the mainline,
    399 and I *suspect* that the mainline version doesn't work with our
    400 openwrt-based device tree which ahs the mdio as a nested node inside
    401 the ag71xx node - in mainline the driver seems to have all the mdio
    402 stuff inline. So, could we build the openwrt driver without patching
    403 the crap out of our kernel
    404 
    405 Sun Oct 16 15:25:33 BST 2022
    406 
    407 Executive decision: let's use the openwrt kernel (at least for
    408 gl-ar750).  Mainline kernel doesn’t have devicetree support for this
    409 device or the SoC it’s based on, and the OpenWrt dts for it doesn’t
    410 have the same "compatible"s, which makes me think that an indefinite
    411 amount of patching will be necessary to make dts/modules for one of
    412 them work with a kernel for the other
    413 
    414 As a result: now we have eth0 appearing, but not eth1?  Guessing we
    415 need to add some kconfig for the switch
    416 
    417 Mon Oct 17 21:23:37 BST 2022
    418 
    419 we are spending ridiculous amounts of cpu/io time copying kernel source
    420 trees from place to place, because we have kernel tree preparation
    421 and actual building as two separate derivations.
    422 
    423 I think the answer is to have a generic kernel build derivation
    424 in the overlay, and then have the device overlays override it with
    425 an additional phase to do openwrt patching or whatever else they
    426 need to do.
    427 
    428 Tue Oct 18 23:02:43 BST 2022
    429 
    430 * previous TODO list is Aug 02, need to review
    431 * dts is hardcoded to gl-ar750, that needs cleaning up
    432 * figure out persistent addresses for ethernet
    433 * fix halt/reboot
    434 * "link" services have a "device" attribute, would much rather
    435   have everything referenced using outputs than having two
    436   different mechanisms for reading similar things
    437 * Kconfig.local do we still need it?
    438 * check all config instead of differentiating config/checkedConfig
    439 
    440 Sun Feb  5 18:14:02 GMT 2023
    441 
    442 We have resumed.
    443 commit eb4efab6a215bf03cf5aab10d4ac909e83e9c148
    444 Author: Daniel Barlow <dan@telent.net>
    445 Date:   Sat Jan 28 23:18:28 2023 +0000
    446 
    447 
    448 * find out what works
    449 * add that stuff to hydra
    450 * fix the rest
    451 * add that stuff to hydra
    452 * convert to flake
    453 * check if routeros can be run interactively
    454 * some per-device docs in a form that can be transcluded for website
    455 
    456 
    457 ci builds
    458 
    459 * each of the tests has hardcoded device/config/etc
    460 * build an "empty" configuration for each target device
    461 * build an unstable configuration for qemu
    462 
    463 
    464 Wed Feb  8 16:52:22 GMT 2023
    465 
    466 We have hydra builds for all the previously-working devices, though we
    467 don't yet know if any of those builds actually boots or does anything
    468 useful.
    469 
    470 [DONE] Would be nice to clean up the run-qemu and connect-qemu scripts
    471 and put them in the buildEnv
    472 
    473 Some thought needed about how to hook up the gl-ar750 to the internets,
    474 ideally in a way that mirrors typical real uses. AAISP have an L2TP
    475 service, but I would prefer to use pppoe on the device, so how to
    476 translate one to t'other on an intermediary/gateway machine?
    477 https://www.rfc-archive.org/getrfc.php?rfc=3817#gsc.tab=0 exists
    478 as an RFC but I can't find anything that actually implements it
    479 
    480 Actual Documentation (e.g.  user and developer manuals) should live in
    481 the liminix repo so it corresponds with the code, and can be rsynced
    482 from there to the web site, maybe with a deploy hook or something.
    483 Haven't decided what a good doc format is yet
    484 
    485 If we create a flake for Hydra to run on, that _more or less_ means we
    486 don't have any manual hydra jobset configuration to document.
    487 
    488 There are still some tests that need adding to CI
    489 
    490 [DONE] Should the per-device config be a module not an overlay? Given that
    491 half of what's in it is kernel config (a module could set this)
    492 and the rest is source tarball download specs (needs nixpkgs,
    493 a module has this and could set it too) I wonder why it isn't already
    494 
    495 [ALREADY DOES] Can we make Hydra report output sizes so we can plot closure size
    496 trends and see if it all goes awful?
    497 
    498 Thu Feb  9 08:14:39 GMT 2023
    499 
    500 For better developer experience, I am thinking that either (1)
    501 swap tasks 2 and 3 (writable filesystem before module system)
    502 or (2) add NBD support so I can iterate on a real device without
    503 full rebuilds every time
    504 
    505 
    506 Fri Feb 10 06:18:25 PM GMT 2023
    507 
    508 did the overlay->module thing
    509 
    510 [DONE] Need to fix all the configuration around PHRAM, I can't see how it
    511 would ever work
    512 
    513 Sat Feb 11 14:37:45 GMT 2023
    514 
    515 Consolidated TODO
    516 
    517 * figure out persistent addresses for ethernet (?)
    518 [SEEMS DONE] * fix halt/reboot
    519 [DONE, NO] * Kconfig.local do we still need it?
    520 [DONE] * check all config instead of differentiating config/checkedConfig
    521 
    522 Things we can do in qemu
    523 
    524 * "link" services have a "device" attribute, would much rather
    525   have everything referenced using outputs than having two
    526   different mechanisms for reading similar things
    527 1) make interface address service that depends on dhcp, instead of
    528   being set by it directly
    529 2) check out restart behaviour of dependent services when depended-on
    530   service dies
    531 3) pppd _creates_ an interface, work out how to fit it into this model
    532 5) add bridge support for lan
    533 8) upgrade ppp to something with an ipv6-up-script option, move ppp and pppoe derivations into their own files
    534 9) get ipv6 address from pppoe
    535 10) get ipv6 delegation from pppoe and add prefix to lan
    536 11) support dhcp6 in dnsmasq, and advertise prefix on lan
    537 12) firewalling and nat
    538  - default deny or zero trust?
    539 14) write secrets holder as a service with outputs
    540 20) should we check that references to outputs actually correspond with
    541   those provided by a service
    542 * Actual Documentation (e.g.  user and developer manuals)
    543 * make a flake
    544 * There are still some tests that need adding to CI
    545 
    546 Things we probably do on hardware
    547 
    548 [DONE] * dts is hardcoded to gl-ar750, that needs cleaning up
    549 6) writable filesystem (ubifs?)
    550 7) overlay with squashfs/ubifs - useful? think about workflows for
    551 how this thing is installed
    552 16) gl-ar750
    553 [DONE] * decide how to hook up the gl-ar750 to the internets
    554 17) mediatek device - gl-mt300 or whatever I have lying around
    555 18) some kind of arm (banana pi router?)
    556 [DONE DIFERENTLY] 19) should we give routeros a hardware ethernet and maybe an l2tp upstream,
    557  then we could dogfood the hardware devices.  we could run an l2tp service
    558  at mythic-beasts, got a /48 there
    559 
    560 
    561 Sat Feb 11 15:57:31 GMT 2023
    562 
    563 The reason we would like to run PPPoE instead of L2TP on the "rotuer" device is
    564 
    565 - closer to real world scenario
    566 - means no need to run dhcp client on the wan interface before we
    567    even get to start the l2tpd
    568 
    569 
    570 Sun Feb 12 14:57:28 GMT 2023
    571 
    572 https://github.com/katalix/go-l2tp#kpppoed
    573 
    574 
    575 Mon Feb 13 04:44:09 PM GMT 2023
    576 
    577 if the gl-ar750 is connected to an ethernet card that linux is ignoring,
    578 we're going to have to set up _some_ qemu thing just to run tftp from.
    579 
    580 Tue Feb 14 17:59:34 GMT 2023
    581 
    582 We should do a derivation that creates an ISO image and a qemu shell
    583 script based on a configuration.nix, and put it in buildEnv. We'll
    584 call it "borderNetVm" :
    585 
    586 > A broadband remote access server (BRAS, B-RAS or BBRAS) routes
    587   traffic to and from broadband remote access devices such as digital
    588   subscriber line access multiplexers (DSLAM) on an Internet service
    589   provider's (ISP) network.[1][2] BRAS can also be referred to as a
    590   broadband network gateway or border network gateway (BNG).[3]
    591 
    592 (for consistency we should rename the "access" qemu socket network to
    593 match whatever we call this)
    594 
    595  rm border.qcow2 ; nix-shell --argstr liminix `pwd`  --argstr nixpkgs `pwd`/../nixpkgs  --argstr unstable `pwd`/../unstable-nixpkgs/ ci.nix -A buildEnv --run "run-border-vm"
    596 
    597 Wed Feb 15 22:56:59 GMT 2023
    598 
    599 configuration for border vm needs to come from somewhere so it's good
    600 for more people than just me
    601 
    602 - pci device for setting up the ethernet
    603 - lns address
    604 - uid so it can do 9p shares? do we need to map things here?
    605 
    606 also need to document the host-side bits so that people can set up
    607 their spare ethernet as vfio
    608 
    609 next step for hacking is to figure out what I was doing with pppoe
    610 
    611 Wed Feb 15 22:59:56 GMT 2023
    612 
    613 docs ...
    614 
    615 * introduction
    616 
    617 * user guide
    618 ** how to build it
    619 ** how to flash it on your device
    620 ** what to put in configuration.nix
    621 ** modules
    622 
    623 * developer guide
    624 ** building/running with qemu
    625 *** emulated upstream
    626 ** building/running on hardware
    627 *** run in place with TFTP
    628 *** emulated upstream
    629 ** CI
    630 ** Roadmap
    631 ** Contributing
    632 
    633 
    634 
    635  nix-shell -p sphinx --run "make -C doc html"
    636 
    637 https://francis.begyn.be/blog/nixos-home-router contains information about avahi reflector
    638 
    639 
    640 Fri Feb 17 00:09:34 GMT 2023
    641 
    642    29 11.282085831 81.187.76.242 → 8.8.8.8      ICMP 106 Echo (ping) request  id=0x0187, seq=2/512, 4
    643    30 11.286314642 90.155.53.19 → 81.187.76.242 ICMP 78 Destination unreachable (Communication admin)
    644 
    645 We're getting packets over the pppoe-l2tp relay thing. Just have to
    646 work out now why we're not routing
    647 
    648 Fri Feb 17 16:54:41 GMT 2023
    649 
    650 Haha.  We weren't routing because we'd used the wrong CHAP password
    651 
    652 
    653 
    654 Fri Feb 17 16:58:27 GMT 2023
    655 
    656 This TODO is for nlnet task 1 and for bits of subsequent tasks that
    657 are annoying enough that I might poke at them anyway:
    658 
    659 
    660 1) gl-ar750, why do we get "ag71xx 19000000.eth: invalid MAC address, using random address"
    661 2) gl-ar750, wifi
    662 3) document services so I can remember how they work. Refer back to Oct 18 for notes that no longer make sense
    663 4) check out restart behaviour of dependent services when depended-on service dies
    664 5) pppd _creates_ an interface, work out how to fit it into this model
    665 6) add bridge support for lan
    666 7) upgrade ppp to something with an ipv6-up-script option, move ppp and pppoe derivations into their own files
    667 8) get ipv6 address from pppoe
    668 9) get ipv6 delegation from pppoe and add prefix to lan
    669 10) support dhcp6 in dnsmasq, and advertise prefix on lan
    670 11) firewalling and nat - default deny or zero trust?
    671 13) should we check that references to outputs actually correspond with
    672 14) make a flake?
    673 15) see if there are other tests that need adding to CI
    674 15a) is bordervm derivation tested?
    675 18) gl-mt300a
    676 19) gl-mt300n-v2
    677 20) publish the manual using CI
    678 
    679 12) write secrets holder as a service with outputs
    680 16) writable filesystem (ubifs?)
    681 17) overlay with squashfs/ubifs - useful? think about workflows for how this thing is installed
    682 
    683 
    684 I could plug tninkpad into the gl-ar750 LAN port to dogfood the wired
    685 networking
    686 
    687 Sat Feb 18 14:26:45 GMT 2023
    688 
    689 Apparently we're not currently doing anything special with busybox,
    690 just using the default nixos build with the default applets.
    691 
    692 We'd like to be able to say in modules which applets they need,
    693 so that we build all necessary applets but don't waste any space.
    694 But we don't want to build a busybox for each module because that
    695 would be a big waste of space.
    696 
    697 One option:
    698 - add busybox configuration to `config` so that modules can maul it
    699 - add a busybox module that builds it with union of all config and
    700  adds link in /bin
    701 - make everything else look in /bin instead of referencing pkgs.busybox
    702 
    703 It would be good if services could assert somehow that their required
    704 config is present
    705 
    706 Sat Feb 18 23:45:13 GMT 2023
    707 
    708 # lsmod
    709 
    710 cd /lib/modules/mac80211
    711 insmod ./compat/compat.ko
    712 insmod ./net/wireless/cfg80211.ko
    713 insmod ./net/mac80211/mac80211.ko
    714 insmod ./drivers/net/wireless/ath/ath.ko
    715 insmod ./drivers/net/wireless/ath/ath9k/ath9k_hw.ko
    716 insmod ./drivers/net/wireless/ath/ath9k/ath9k_common.ko
    717 insmod ./drivers/net/wireless/ath/ath9k/ath9k.ko
    718 insmod ./drivers/net/wireless/ath/ath10k/ath10k_core.ko
    719 insmod ./drivers/net/wireless/ath/ath10k/ath10k_pci.ko
    720 
    721 [21.344930] ath9k 18100000.wmac: failed to load calibration data from mtd device
    722 [21.352728] ath: phy0: parsing configuration from OF node
    723 [21.362576] ath: phy0: serialize_regmode is 0
    724 [21.367092] ath: phy0: UNDEFINED -> AWAKE
    725 [21.372051] ath: phy0: Trying EEPROM access at Address 0x03ff
    726 [21.377999] ath: phy0: Trying EEPROM access at Address 0x0fff
    727 [21.383940] ath: phy0: Trying EEPROM access at Address 0x01ff
    728 [21.389879] ath: phy0: Trying OTP access at Address 0x03ff
    729 [21.400396] Data bus error, epc == 8027964c, ra == 83125880
    730 [21.406156] Oops[#1]:
    731 
    732 
    733 Sun Feb 19 18:15:27 GMT 2023
    734 
    735 We have ath9k listening for packets. To make this ready to use:
    736 
    737 - need to load the modules
    738 - enable bridging lan with wlan
    739 - packet forwarding
    740 - firewall
    741 
    742 
    743 Mon Feb 20 20:41:17 GMT 2023
    744 
    745 need to fix all the other broken ci jobs :-(
    746 
    747 The wlan test is failing because we moved mac80211 to a module and
    748 there's nothing running to insmod it
    749 
    750 Wed Feb 22 18:17:17 GMT 2023
    751 
    752 bridge is e2b3738d0f8c3f2fd76ebcef65612de502a7b121 but it's the wrong
    753 way around: the master interface needs to be up whether or not all
    754 of its children are, so members depend on master not vice versa
    755 
    756 Next steps:
    757 - re-implement bridge, enable bridging lan with wlan
    758 - packet forwarding
    759 - firewall
    760 - ath10k
    761 - ipv6
    762 
    763 Fri Feb 24 23:37:56 GMT 2023
    764 
    765 bridging wlan was made complex because can't add a device to a bridge
    766 until it's operational, and wlan0 is not operational until hostapd
    767 has churned awhile. Therefore, "waitup" listens for netlink messages
    768 and notifies s6 readiness stuff
    769 
    770 we have a firewall nft script but we're not running it on boot
    771 
    772 we have forwarding but no dns, maybe because we haven't told
    773 dnsmasq about any upstream servers
    774 
    775 Sun Feb 26 21:08:47 GMT 2023
    776 
    777 to add firmware we need to put files in /lib/firmware, which means
    778 a module
    779 
    780 i guess we should do that in the device module
    781 
    782 we can create the firmware files as packages
    783 
    784 
    785 for the cal data we would like to get it from the device MTD "art"
    786 partition at
    787 boot time.
    788 
    789 f
    790 ====from openwrt
    791 
    792 
    793 
    794 case "$FIRMWARE" in
    795 "ath10k/cal-pci-0000:00:00.0.bin")
    796         case $board in
    797         allnet,all-wap02860ac|\
    798         araknis,an-500-ap-i-ac|\
    799         araknis,an-700-ap-i-ac|\
    800         engenius,eap1200h|\
    801         engenius,enstationac-v1|\
    802         glinet,gl-x750|\
    803         watchguard,ap300)
    804                 caldata_extract "art" 0x5000 0x844
    805                 ath10k_patch_mac $(macaddr_add $(mtd_get_mac_binary art 0x0) 2)
    806 
    807 
    808 
    809 
    810 caldata_extract part offset count
    811       caldata_dd $mtd /lib/firmware/$FIRMWARE $count $offset || \
    812                 caldata_die "failed to extract calibration data from $mtd"
    813         dd if=$source of=$target iflag=skip_bytes,fullblock bs=$count skip=$offset count=1 2>/dev/null
    814 
    815 =======
    816 
    817 part=$(basename $(dirname $(grep -l art /sys/class/mtd/*/name)))
    818 dd if=/dev/$part \
    819   of=/run/cal-pci-0000:00:00.0.bin iflag=skip_bytes,fullblock \
    820   bs=0x844 skip=0x5000 count=1
    821 
    822 Mon Feb 27 22:46:37 GMT 2023
    823 
    824 Found and fixed a bunchg of things that were stopping ath10k from
    825 working. The remaining problem is (I think) that insmod is not
    826 synchronous, so "ip link set up dev wlan1" doesn't work immediately
    827 after the module is inserted. Maybe we need another netlink thing
    828 to wait until the interface is present.
    829 
    830 
    831 Wed Mar  1 18:26:44 GMT 2023
    832 
    833 ath10k works, but the wlan module loading stuff is quite kludgey
    834 
    835 I wonder if wlan0, wlan1, eth0, eth1 etc should be defined per-device
    836 - how does the aplication config know which devices exist? If we
    837 decide to switch to some form of persistent device naming, the names
    838 will differ from one device to the next. Perhaps the device should
    839 also provide standard names where possible?
    840 
    841 services.network.links = {
    842   lan = interface { ... };
    843   wan = interface { ... };
    844   wlan_24 = interface { ... };
    845   wlan_5 = interface { ... };
    846 }
    847 
    848 Thu Mar  2 22:45:11 GMT 2023
    849 
    850 We have a flashable image!
    851 
    852 Now we can use the gl-ar750 for internet access in the shed, we can
    853 apppropriate the other device that's in there and try Liminix on it
    854 
    855 Fri Mar  3 23:08:58 GMT 2023
    856 
    857 If we're going to unplug serial console from the gl-ar750 maybe we
    858 should install an ssh server first.
    859 
    860 0) set a root password
    861 1) allow setting a root password from configuration.nix
    862 (means defining config.users properly)
    863 2) allow authorizedKeys per user
    864 3) dropbear service
    865 4) see if the wired lan works! :-)
    866 
    867 
    868 Sat Mar  4 12:31:07 GMT 2023
    869 
    870 To improve logging, each service should have its own s6-log service
    871 which prefixes the service name onto the log line and then sends to
    872 stdout
    873 
    874   https://skarnet.org/software/s6/servicedir.html
    875   https://skarnet.org/software/s6/s6-log.html
    876 
    877 As far as I can tell, the `log` directory inside the service
    878 directory should itself be a service directory for the s6-log
    879 process that does this
    880 
    881 .... hahaha no that doesn't work
    882 
    883 s6-rc, for some reason, ignores the `log` directory and requires
    884 that loggers be done with consumer-for and producer-for instead
    885 
    886 
    887 Sat Mar  4 23:27:00 GMT 2023
    888 
    889 notes for this week's news update
    890 
    891 * ath10k kernel support and and firmware
    892 
    893 - 5GHz wifi works
    894 
    895 - need to retrieve the firmware from a special - partition on the
    896   device itself, so we do that using a service that - the wlan
    897   interface depends on
    898 
    899 * replace waitup with more generally useful ifwait
    900 
    901 to make the ath10k load at boot, we need to insert the module and then
    902 wait for it to do something or other in the background before we can
    903 configure the interface. so we need something like waitup but
    904 for presence not operational state
    905 
    906 it turns out that a program that just waits for a particular interface
    907 state and then exits is quite simple to add into run scripts and
    908 we don't need all that notification-fd stuff anyway
    909 
    910 * move FW_LOADER* config to modules/base
    911 
    912 * rejig config a bit.
    913 - device hardware characteristics are now under
    914   the `hardware` key and include the available network interfaces.
    915 - options for users and groups are now defined a bit more
    916   specifically than "attrset", making it possible to e.g. set a
    917   root password
    918 - dts is moved from `boot` to `hardware`
    919 
    920 
    921 * now producing flashable images, so you can generate a liminix config
    922 and write it to the device instead of having to boot using TFTP and
    923 a serial console every time
    924 
    925 * ssh support
    926 
    927 * prefix logs with the service name
    928 
    929 Sun Mar  5 22:51:21 GMT 2023
    930 
    931 Added swconfig: it was a straight copy from nixwrt and hasn't changed
    932 upstream since. But don't need it, because the lan port works fine
    933 without it (I assume both lan ports and the cpu are all connected
    934 untagged)
    935 
    936 Mon Mar  6 09:42:33 GMT 2023
    937 
    938 Today I plugged in the mt300a.
    939 
    940 echo 17 >/sys/class/gpio/export
    941 echo out >/sys/class/gpio/gpio17/direction
    942 
    943 
    944 why are our images getting big
    945 
    946 - lua links ncurses
    947 - hostapd links openssl and sqlite
    948 - nftables needs
    949   - iptables?
    950   - jansson? what is that?
    951   - libedit/readline
    952 - ifwait needs bash
    953 
    954 
    955   File: result/squashfs
    956   Size: 10371072        Blocks: 20256      IO Block: 4096   regular file
    957 
    958 with smaller nftables:    9617408        Blocks: 18784
    959 
    960 hostapd wqithout sqlite   9003008        Blocks: 17584
    961 
    962 without bash:             8622080         Blocks: 16840      IO Block: 4096   regular file
    963 
    964 without lua readline: bigger?!  8769536         Blocks: 17128      IO Block: 4096   regular file
    965 
    966 
    967 Mon Mar  6 20:57:49 GMT 2023
    968 
    969 [    0.539992] mtk_soc_eth 10100000.ethernet: mdio-bus disabled
    970 [   10.493918] platform regulatory.0: Direct firmware load for regulatory.db fail
    971 ed with error -2
    972 [   10.502828] cfg80211: failed to load regulatory.db
    973 
    974 Check in morning, but whichever port the ethernet cable is plugged into,
    975 is considered by the kernel as port 0 - which I think we should treat as
    976 WAN
    977 
    978 VLAN 1:
    979         vid: 1
    980         ports: 1 2 3 4 5 6t
    981 VLAN 2:
    982         vid: 2
    983         ports: 0 6t
    984 
    985 ip link add link eth0 name lan type vlan id 1
    986 ip link add link eth0 name wan type vlan id 2
    987 
    988 figure out how to add these to gl-mt300a device config
    989 then extedner.nix can add a bridge
    990 
    991 Tue Mar  7 20:13:15 GMT 2023
    992 
    993 We need NTP or some other way to get accurate time
    994 
    995 [done] Need to add regulatory.db somewhere standard, maybe modules/wlan?
    996 
    997 Tue Mar  7 21:43:56 GMT 2023
    998 
    999 When we get to phase 2, need to review how network interfaces and
   1000 their addresses interplay. It should be possible to have a network
   1001 interface and interrogate the addresses associated with it - esp
   1002 with ipv6 where there are multiple addresses for the device
   1003 
   1004 This thought prompted by looking at the loopback interface, which is
   1005 a bundle of addresses and therefore we can't see what any of them are
   1006 
   1007 
   1008 Tue Mar  7 22:05:44 GMT 2023
   1009 
   1010 [phase 1]
   1011 20) publish the manual using CI
   1012 30) document flashing process
   1013 31) go through all the unexpected dmesg and triage it
   1014 25) ntp or some other accurate time source
   1015 
   1016 [phase 1.5]
   1017 26) ssh keys
   1018 8) get ipv6 address from pppoe
   1019 9) get ipv6 delegation from pppoe and add prefix to lan
   1020 10) support dhcp6 in dnsmasq, and advertise prefix on lan
   1021 11) firewalling and nat - default deny or zero trust?
   1022 7) upgrade ppp to something with an ipv6-up-script option, move ppp and pppoe derivations into their own files
   1023 32) set up iperf and do some performance measurement
   1024 35) also we need to check our wireless country code
   1025 
   1026 
   1027 [phase 2]
   1028 3) document services so I can remember how they work. Refer back to Oct 18 for notes that no longer make sense
   1029 4) check out restart behaviour of dependent services when depended-on service dies
   1030 13) check that references to outputs correspond with declared outputs
   1031 33) network interfaces vs the services that manage their addresses
   1032 34) write a short guide explaining how to use s6-svc
   1033 
   1034 [phase n]
   1035 12) write secrets holder as a service with outputs
   1036 16) writable filesystem (ubifs?)
   1037 17) overlay with squashfs/ubifs - useful? think about workflows for how this thing is installed
   1038 
   1039 
   1040 dmesg lines to investigate for gl-mt300a:
   1041 [    0.467314] OF: Bad cell count for /palmbus@10000000/spi@b00/flash@0/partition
   1042 [    0.539709] mtk_soc_eth 10100000.ethernet: mdio-bus disabled  ?
   1043 [    8.778513] compat: loading out-of-tree module taints kernel.
   1044 [   17.686561] ieee80211 phy0: rt2800_wait_bbp_rf_ready: Error - BBP/RF register access failed, aborting
   1045 [   17.696025] ieee80211 phy0: rt2800_loft_iq_calibration: Warning - RF RX busy in LOFT IQ calibration
   1046 [   17.875147] ieee80211 phy0: rt2800_rxiq_calibration: Warning - Timeout waiting for MAC status in RXIQ calibration
   1047 
   1048 for gl-ar750:
   1049 [    0.000000] Unknown kernel command line parameters "earlyprintk=serial,ttyS0", will be passed to user space.
   1050 [    0.416679] OF: Bad cell count for /ahb/spi@1f000000/flash@0/partitions
   1051 [    0.825495] ag71xx 19000000.eth: Could not connect to PHY device. Deferring probe.
   1052 [    1.632700] pci_bus 0000:00: root bus resource [mem 0x10000000-0x13ffffff]
   1053 [    1.639824] pci_bus 0000:00: root bus resource [io  0x0000]
   1054 [    1.645601] pci_bus 0000:00: No busn resource found for root bus, will use [bus 00-ff]
   1055 [   32.032326] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
   1056 [   36.627844] ath10k_pci 0000:00:00.0: failed to receive initialized event from target: 00000000
   1057 
   1058 
   1059 Fri Mar 10 13:17:56 GMT 2023
   1060 
   1061 Lunchtime notes on images for real devices, vs ci.nix
   1062 
   1063 * successfully building an image doesn't mean that the image boots
   1064 or does anything useful
   1065 
   1066 * don't want to faff with serial wires on every device every time
   1067 to test it. so
   1068 
   1069 * ideally, build ram-based images of rotuer, extneder, arhcive in CI
   1070 with a watchdog timer that will reboot if it can't see the network
   1071 
   1072 * figure out how to boot into the new image from an ssh connection.  I
   1073 assume the challenging bit here is grabbing x MB of contiguous phys
   1074 mem after boot: I think we'd have to reserve it at _first_ boot and
   1075 then somehow copy into it before rebooting
   1076 
   1077 An easier first goal might be a tool to flash from the shell command line,
   1078 but that runs a greater risk of bricking
   1079 
   1080 
   1081 Fri Mar 10 14:35:40 GMT 2023
   1082 
   1083 programs.busybox = {
   1084   enable = true;
   1085   applets = [... ];
   1086   config = {
   1087   };
   1088 }
   1089 
   1090 Fri Mar 10 23:49:04 GMT 2023
   1091 
   1092 Well, we have the backup host config up and running - though haven't
   1093 plugged it back into its disk yet.
   1094 
   1095 For task 1 what remains is
   1096 
   1097 1) ntp sync
   1098 2) write up the flashing procedure
   1099 3) a video?
   1100 
   1101 
   1102 Sat Mar 11 13:58:20 GMT 2023
   1103 
   1104 ================== for video
   1105 
   1106 what is liminix
   1107 - nix-based system for creating OS images for routers
   1108 - not "nixos on your router"
   1109   - nixos-like module system,
   1110   - musl for libc
   1111   - s6/s6-rc for services
   1112   - entirely cross-compiled
   1113 
   1114 why am i making a video?
   1115 - unless you have a suitable spare device to install on,
   1116   and you want to take it apart, it's currently hard to
   1117   take liminix for a spin
   1118 - I have these things, so I can give you a tour
   1119 
   1120 let's have a look at how the hardware's hooked up
   1121 
   1122 web site & manual
   1123 
   1124 a config file:
   1125 - observe the comments:
   1126   - not going to spend ages on this because it's not in its final form.
   1127   - as we get more configs for more use cases, we will
   1128     get a better feel for what can be abstracted
   1129   - that will come later: work so far has been on the
   1130     hardware support side
   1131 
   1132 to show that it builds, we're going to add a package. otherwise,
   1133 everything from this build is probably already cached
   1134 
   1135 build the config
   1136 
   1137 tftpboot on hardware
   1138 
   1139 flash on hardware
   1140 
   1141 show ci
   1142 
   1143 show a qemu target
   1144 
   1145 Mon Mar 13 22:46:46 GMT 2023
   1146 
   1147 1) rsync on arhcive is failing because no nogroup group
   1148 
   1149   "/nix/store/gfzzl157r8xyp38lpcfxydkiiy6zrs3c-rsync-3.2.6/bin/rsync" "--verbose" "--stats" "--password-file" "/etc/nixos/secrets/arhcive-rsync" "-rltgoDz" "/var/spool/backup" "backup@arhcive.lan::srv/"
   1150 @ERROR: invalid gid nogroup
   1151 rsync error: error starting client-server protocol (code 5) at main.c(1837) [sender=3.2.6]
   1152 
   1153 2) we can run findfs in a loop until the disk appears
   1154 
   1155 3) still haven't decided how to do ntp but maybe we should just use
   1156 the busybox one
   1157 
   1158 4) some way to do upgrades over the wire
   1159 
   1160 - boot with reserved mem and a phram device at 110-128MB even in the
   1161   flashable version
   1162 
   1163 - watchdog timer in kernel
   1164 
   1165 - kexec in kernel
   1166 
   1167 - userland service to feed the dog as long as local network is up
   1168  (may need to start it a couple of minutes after boot, how do we
   1169   do that?)
   1170 
   1171 - can we use flashcp on a phram mtd?
   1172 
   1173 5) maybe setup a vhost for hydra or something
   1174 
   1175 [nix-shell:~/t]$ wget --reject-regex '\?' -D localhost -N -r --exclude-directories=/api --level=2 --convert-links -e robots=off http://localhost:3003/jobset/liminix/build/
   1176 
   1177 is almost a mirror
   1178 
   1179 Tue Mar 14 20:17:35 GMT 2023
   1180 
   1181 - do we have a phram mtd? need config for size and location
   1182 
   1183 - how do we set the boot device
   1184  - for first boot need to boot real flash, use  dtb, ignore bootloader args
   1185  - for kexec, boot phram, specify args somehow (could rewrite dtb)
   1186 
   1187  => can use same kernel for both if we can give kexec a dtb with
   1188     different params, which seems to be possible
   1189 
   1190 so we need a module for the initial kernel to say
   1191 - create phram mtd
   1192 - boot from real mtd (will be index + 1)
   1193 - enable KEXEC in kernel
   1194 - add kexec-tools
   1195 
   1196 and for the kernel we boot into
   1197 - most of the above
   1198 - except for the boot device
   1199 - create an output with objects that kexec(8) can parse
   1200 
   1201 Could be same module for both with different outputs
   1202 
   1203 what do we call this thing? "revertable"
   1204 
   1205 Wed Mar 15 19:11:09 GMT 2023
   1206 
   1207 "revertable" implies mtd support for the rootfs and a ramdisk at
   1208 defined location
   1209 
   1210 "tftpboot" implies "revertable", because it will use the same ramdisk
   1211 
   1212 
   1213 Fri Mar 17 11:44:40 GMT 2023
   1214 
   1215 - patch the kernel kexec code to pass DTB to new kernel unconditionally
   1216 - unpatch pernel to pass command line to kexec (breaks DTB passing)
   1217 - decide how we specify rootfs. doing it by number is awkward
   1218   - may be phram
   1219   - may be real mtd root
   1220   - may be real mtd root but renumbered becuase phram exists
   1221 
   1222 Wild idea: we could probably get rid of the need for declaring a phram
   1223 device in the first kernel, if we can use kexec to copy the squashfs into
   1224 physical ram. As far as I can see this is a simple(sic) matter of
   1225 specifying it as a segment, but we would have to extend kexec-tools
   1226 to do this and it's quite a niche option if we make it do all the
   1227 mtd setup.
   1228 
   1229 kexec --dtb=foo.dtb --map-file=squashfs@0x120000
   1230 
   1231 
   1232 Sat Mar 18 18:02:26 GMT 2023
   1233 What if: we added derivations for "apply openwrt changes" as packages,
   1234 which could then be called from the kernel derivation's extraPatchPhase?
   1235 There could be one for generic and one for each openwrt targetop
   1236 
   1237 Mon Mar 20 18:40:53 GMT 2023
   1238 
   1239 - kexec patch is sent to mailing list, keep an eye for replies
   1240 - watchdog
   1241 - ntp
   1242 - rebuild images for live devices
   1243 - can we build a static busybox with flashcp applet and scp it
   1244  to arhcive etc?
   1245 - [DONE] install mailman and hyperkitty on myhtic, create mailing list
   1246 
   1247 Tue Mar 21 22:59:54 GMT 2023
   1248 
   1249 I haven't found a way to arm the watchdog before userland runs, which
   1250 would be really nice: although there's WATCHDOG_HANDLE_BOOT_ENABLED
   1251 and WATCHDOG_OPEN_TIMEOUT it doesn't seem to be sufficient, Maybe
   1252 those options work only when the hardware watchdog is already
   1253 armed. It might not be completely awful insofar as any failure to
   1254 mount root usually results in panic anyway, so provided we start
   1255 watching early in boot then there's not a big window for anything
   1256 to go wrong
   1257 
   1258 What should the watchdog service do?  Ideally we want something that
   1259 "ratchets" : can be started in early boot and signals health as long
   1260 as the system is starting up, then once the system is in "steady
   1261 state" it stops pinging as soon as any part of that steady state
   1262 becomes unhealthy. This feels like a refinement for a much later
   1263 phase though.
   1264 
   1265 Maybe the health criteria might be
   1266 (sshd and lan services are running) or (time since boot < 120s)
   1267 
   1268 Thu Mar 23 00:11:23 GMT 2023
   1269 
   1270 tftpboot and (kexecboot || flashable) have incompatible DTB-finding
   1271 strategies which is painful if you add both modules and then
   1272 expect tftp booting to still work
   1273 
   1274 Maybe we could patch the kernel to use some better strategy for when
   1275 to use/ignore the bootloader command line: e.g "only if it
   1276 contains the string 'liminix'". Could do this by patching
   1277 arch/mips/kernel/setup.c bootcmdline_init to
   1278 
   1279 if(strstr(arcs_cmdline, "liminix") == NULL) arcs_cmdline[0] = '\0'
   1280 and then defining CONFIG_MIPS_CMDLINE_DTB_EXTEND. The
   1281 bootloader command line then needs to specify only the
   1282 _additional_ parameters that weren't in the DTB
   1283 
   1284 (later: that turned out to be quite straighforward)
   1285 
   1286 Fri Mar 24 23:45:12 GMT 2023
   1287 
   1288 - add ntp support
   1289 - [DONE] expose hydra to internet
   1290 - check MAC address weirdness?
   1291 - call Task 1 "done"
   1292 
   1293 Sun Mar 26 00:19:15 GMT 2023
   1294 
   1295 Would be nice to have a flash.sh built in outputs.flashable
   1296 
   1297 Sun Mar 26 15:27:14 BST 2023
   1298 
   1299 Let's think about services and modules.
   1300 
   1301 Module
   1302 + can change global config
   1303   * add users, groups etc
   1304   * change kernel config
   1305   * change busybox config
   1306 + well-typed parameters
   1307 - is a "singleton": can't have the same module included twice
   1308   with different config. e.g. can't have two hostap modules running on
   1309   different wlan radios.
   1310 - can't express dependencies: a depends on b
   1311 
   1312 suppose:
   1313 
   1314 * modules add service functions to the config? then there's no
   1315 way to define a service while forgetting to import the module
   1316 
   1317 * we use the lib.types stuff for service function arguments
   1318 
   1319 * maybe we stop naming services.foo for every damn thing
   1320 
   1321 * but remember, s6 services do need unique names
   1322 
   1323 
   1324 imports = [ ../modules/dhcp4 ];
   1325 
   1326 services.dhcp4 = config.services.udhcp {
   1327   interface = lan.device;
   1328   options = {
   1329     foo = true;
   1330     bar = 42;
   1331   };
   1332   depends = [ services.some_other_thing ];
   1333 }
   1334 
   1335 modules/dhcp4 udhcp fn needs to define a type for its argument, then
   1336 use something like
   1337 
   1338   if arg_type.check def.value then res
   1339             else throw "The option value `${showOption loc}' in `${def.file}' is not a ${arg_type.name}.")
   1340 
   1341 (where def comes from I don't know yet)
   1342 
   1343 Tue Mar 28 10:44:40 BST 2023
   1344 
   1345 we should reserve the name "service" for actual instantiated
   1346 services. This means we need a name for the functions that
   1347 make services. "class", "template", "fn", "maker", "factory"?
   1348 And a namespace name so they're not interleaved with real
   1349 services, which sort of suggests they are packages
   1350 
   1351 if we want to do services = {
   1352  foo = longrun { ... };
   1353  bar = longrun { ... };
   1354 }
   1355 
   1356 without repeating the `name` as an attribute of the longrun,
   1357 then longrun can't return a derivation: it has to return some
   1358 function that accepts `name` as a parameter.
   1359 
   1360 where services.a depends on services.b, at the time its builder is run
   1361 it needs to know what name s6-rc will use for service b
   1362 
   1363 maybe an s6 service definition should be an attrset not a derivation.
   1364 
   1365 maybe this is outside scope for phase 2
   1366 
   1367 Tue Mar 28 13:22:06 BST 2023
   1368 
   1369 Reading nixos/doc/manual/development/building-parts.chapter.md it
   1370 suggests to me that we should rename config.outputs to
   1371 config.system.outputs. The more general question here is whether it's
   1372 good to be augmenting a variable called "config" with all this
   1373 generated stuff that is patently not configuration - perhaps putting
   1374 it under a "system" key will keep it all in one place
   1375 
   1376 Tue Mar 28 13:32:30 BST 2023
   1377 
   1378 how should we handle filesystem state? e.g. resolvconf service
   1379 
   1380 if a service provides a file at a known global pathname, it can't be
   1381 parametrised - it must be a singleton.
   1382 
   1383 Tue Mar 28 20:25:20 BST 2023
   1384 
   1385 wondering if we should swap phases 2 and 3. We can't really address
   1386 modules without addressing services, which is phase +n, whereas we
   1387 can tackle overlay/ubi whenever
   1388 
   1389 nand flash may have bad blocks
   1390 nor flash (supposedly) doesn't
   1391 
   1392 ubi provides erase counts and bad block remapping on top of the mtd
   1393 interface. this means we should avoid flashcp of a ubi image straight
   1394 onto (nand) mtd as we will lose the erase counts and bad block information
   1395 that UBI tracks.
   1396 
   1397 overlayfs works on a filename basis, so might not be very effective :
   1398 any change that results in a new store path will mean the entire package
   1399 appears in two places. I think it's reasonable to offer squashfs or
   1400 ubifs without overlay.
   1401 
   1402 open questions:
   1403 
   1404 1) if uboot doesn't support UBI, we can't boot a kernel on a ubifs
   1405 so we need reserved space for the kernel.
   1406 
   1407 - unless we add some padding after the kernel, every new kernel
   1408 that's bigger than its predecessor will trash the start of the
   1409 ubi space (and wipe out its erase count)
   1410 - This suggests we should build more stuff as modules and less as
   1411 compiled-in
   1412 
   1413 2) once a device has had a ubi volume created on it, probably we want
   1414 to use ubi-aware tools to update that volume in future instead of a
   1415 whole new flash, because we wish to preserve erase counts. This means
   1416 running ubiformat --image-file=foo.ubi on the device instead of flashcp
   1417 
   1418 we can add a "ubi-flashable" output that creates a .ubi image and
   1419 a flashcp image that wraps it, with instructions on which to use.
   1420 
   1421 Fri Mar 31 22:13:54 BST 2023
   1422 
   1423 Error: too small LEB size 3968, minimum is 15360
   1424 
   1425 > This error means that you are trying to mount too small UBI
   1426 volume. Probably because your flash is too small? Try to use JFFS2,
   1427 then, because it suits small flashes better since it has much lower
   1428 space overhead. Indeed, UBIFS stores much more indexing information on
   1429 the flash media than JFFS2, so it has much higher overhead. Also, UBI
   1430 has some overhead (see here). Thus, if you have a small flash device
   1431 (e.g., about 64MiB), it makes sense to consider using JFFS2.
   1432 
   1433 
   1434 Argh. Oh well,
   1435 
   1436 Sat Apr  1 15:27:39 BST 2023
   1437 
   1438 There's limited value in recreating pseudofiles for jffs2 because
   1439 the system is writable - changes made to /bin, /dev etc in config.filesystem
   1440 should take effect on a running system.
   1441 
   1442 Can we take inspiration from https://grahamc.com/blog/erase-your-darlings/ ?
   1443 
   1444 in early boot:
   1445  mount ramfs on /
   1446  mount the writeable filesystem on /persist/
   1447  bind mount /persist/nix on /nix
   1448  run script to populate rootfs from pseudofiles
   1449 
   1450 on a router, do we need _anything_ persistent that's outside the store?
   1451 
   1452  - state for dhcp leases and stuff
   1453  - secrets
   1454  - maybe, files that the user has downloaded
   1455 
   1456 this will probably require initramfs. if just use jffs2 as the rootfs and
   1457 don't worry about /persist, we can skip that step.
   1458 
   1459 
   1460 
   1461 
   1462 [ aside: I think we may be putting two busyboxes in the image:
   1463 see modules/s6/default.nix s6-init-scripts has buildInputs = [busybox];  ]
   1464 
   1465 Mon Apr  3 18:34:26 BST 2023
   1466 
   1467 suppose
   1468 - we boot the system with systemConfig=/nix/store/eeeeee-system
   1469 - the early-init script runs /target/$systemConfig/create-root /target
   1470   after mounting /target
   1471 - then it runs chroot /target $systemConfig/bin/init "$@"
   1472 
   1473 or maybe we could combine those steps?
   1474 or maybe it doesn't matter too much ...
   1475 
   1476 Thu Apr  6 21:25:41 BST 2023
   1477 
   1478 what now?
   1479 
   1480 - put a jffs2 onto some hardware device
   1481   - what do we do with uboot?
   1482   - should we pad the kernel?
   1483   - maybe kernel module support would be good if we're making it
   1484     hard to do kernel updates
   1485 - try the nix-copy-closure thing and work out what else we don't know
   1486 - [done] detect endian correctly
   1487 
   1488 
   1489 to ask a different question, what else do we need to dogfood a router?
   1490 
   1491 Sun Apr  9 10:06:08 BST 2023
   1492 
   1493 - rename outputs.flashable to outputs.flashimage
   1494 - rename modules/flashable to modules/flashable_ro
   1495 - create outputs.flashable in modules/jffs2
   1496 - rename modules/jffs2 to modules/flashable_rw
   1497 - add enable config to both?
   1498 - enable kernel module compilation
   1499 
   1500 
   1501 Mon Apr 10 23:50:41 BST 2023
   1502 
   1503 - initramfs parses /proc/cmdline to find root fs, might not play
   1504 nice with defaulting
   1505 
   1506 - how to build kernel modules
   1507 
   1508 - look at closure size, is it this big because we've broken it
   1509 or is jffs2 usually this much bigger than squashfs
   1510 
   1511 - maybe squashfs with overlay might be better if we could
   1512 ensure hardlinks?
   1513 
   1514 - maybe there's something like overlayfs but content-addressable?
   1515 
   1516 Sat Apr 15 18:57:46 BST 2023
   1517 
   1518 for the same configuration:
   1519 
   1520 -r--r--r-- 1 root root 6066176 Jan  1  1970 /nix/store/0x271rg45mcjjgbma9wi31h1yd109fpy-frob-squashfs
   1521 -r--r--r-- 1 root root 12255232 Jan  1  1970 /nix/store/zx11adagcbzqsnqkyz5kgvr392vhlrpr-make-jffs2
   1522 
   1523 may want to reconsider not using squashfs with overlay
   1524 
   1525 Wed Apr 19 22:22:48 BST 2023
   1526 
   1527 Where next?
   1528 
   1529 Sun Apr 23 18:24:34 BST 2023
   1530 
   1531 - we are down to ~ 11MB image for a barely functional (IPV4) router
   1532   this is by avoiding all dependencies on openssl or gnutls
   1533 - rotuer is not recognising when  I set the hostname
   1534 - I may have forgotten the root password :-(
   1535 - why is hello world 70K unless hardeningDisable?
   1536 
   1537 Fri Apr 28 20:51:52 BST 2023
   1538 
   1539 To do nix-copy-closure we need nix-store, which is a symlink to nix,
   1540 which is
   1541 
   1542 -rwxr-xr-x 1 dan users 2.3M Apr 28 21:08 nix
   1543 
   1544 (stripped). This is a lot bigger than, say, a simple script to
   1545 loop through the closure of a derivation and copy only the store
   1546 folders that don't exist already.
   1547 
   1548 * we'd like to only transmit the packages that aren't already present
   1549 
   1550 * we'd like to use a single ssh connection
   1551 
   1552 
   1553 S: here is a list of package names
   1554 C: these are the names of the packages I want
   1555 S: here are the packages
   1556 
   1557 while read $f ; do
   1558   test -d $f || echo $f
   1559 end
   1560 
   1561 Tue May  2 21:53:08 BST 2023
   1562 
   1563 1) we have a script that runs on the receiver, which
   1564 
   1565  - accepts a list of store paths
   1566  - prints the missing store paths
   1567  - runs cpio -i < stdio
   1568 
   1569 2) we need a script for the sender that
   1570 
   1571  - refs=$(nix-store -q --references $1 && echo end)
   1572  - opens ssh connection
   1573  - print ssh $refs
   1574  - needed= capture result until "end" received
   1575  - find needed | cpio -o  > ssh-connection
   1576  - close connection
   1577 
   1578 3) to have a reasonable hope of testing this we should do it with qemu. It would be nice
   1579 if we could connect without faff to the qemu lan interface : either we do this by bringing up
   1580 another qemu vm (preferably with the host store shared, otherwise it has to build a mips cross
   1581 compiler/libc) or maybe we could do something unholy with ssh ProxyCommand
   1582 
   1583 ssh -o ProxyCommand "socat - UDP4-DATAGRAM:230.0.0.1:1234,sourceport=1234,reuseaddr,ip-add-membership=230.0.0.1:127.0.0.1"
   1584 
   1585 
   1586 
   1587 4) we haven't solved garbage collection, though I think "remove everything not in
   1588 nix-path-registration" might be what's needed there
   1589 
   1590 Wed May  3 22:01:19 BST 2023
   1591 
   1592 Something weird is going on with qemu net device enumeration: when I
   1593 run it interactively I'm getting the access network (mac ending :02)
   1594 on eth0 and the lan (mac ending :01) on eth1, and if it's behaving the
   1595 same in CI then how come any of the tests work? vanilla-confinguration.nix
   1596 definitely assumes lan=eth0
   1597 
   1598 By switching from  -device virtio-net-pci to     -device virtio-net then
   1599 I get the desired behaviour back
   1600 
   1601 Sat May  6 18:42:28 BST 2023
   1602 
   1603 Next:
   1604 
   1605 - package min-copy-closure
   1606 - see if we can use it on some output to copy the whole system closure
   1607 - post-copying symlink munging
   1608 - try it on a real device, see if it works for config file updates
   1609 - collect-garbage/delete-old-generation
   1610 
   1611 
   1612 Sun May  7 23:03:03 BST 2023
   1613 
   1614 Shortly after all the work to reduce system closure size last time, I
   1615 tried adding the necessary packages to support nix-copy-closure and
   1616 saw it start building a complete C++ system with Boost. My fears that
   1617 this would lead to quite a large increase in the system size were, it
   1618 turned out, entirely founded.
   1619 
   1620 So I wrote my own - or at least, a quite minimal substitute. The core
   1621 logic is simple - on the sender, we get the list of required packages,
   1622 then we check for the existence of `/nix/store/eeeeeee-foo` for
   1623 each of them on the target, and whatever's missing we send across the
   1624 link using cpio.
   1625 
   1626 It sounds simple, and it should be simple, and in retrospect it _was_
   1627 simple. Along the way I went on a bit of a Qemu networking tangent and
   1628 learned quite a lot about the bash `coproc` command
   1629 
   1630 Tue May  9 21:06:53 BST 2023
   1631 
   1632 General direction of my thoughts:
   1633 
   1634 - get a baseline working rotuer system
   1635 - prove that min-copy-closure works with it
   1636 - refactor the crap out of it
   1637 - configurablise the bordervm usb ethernet setup
   1638 - when we have a good idea of how/whether min-copy-closure *actually*
   1639  works, declare "writeable filesystem" to be done
   1640 - start to get more of a feel for how the services/config hang together
   1641 
   1642 ? why does rotuer not have a hostname?
   1643 
   1644 ? how can we get a device hooked up to rotuer's lan port that we can
   1645 control remotely
   1646 
   1647 Sun May 14 23:25:46 BST 2023
   1648 
   1649 the outputs.systemConfiguration attribute builds a derivation
   1650 containing a single file bin/activate
   1651 
   1652 _Presumably_, copying its closure will copy all the things, as
   1653 we already use it as the roots for jffs2 creation. However, there
   1654 is also a symlink created from /init at jffs2 creation
   1655 
   1656 Mon May 15 21:32:38 BST 2023
   1657 
   1658 Had a neat idea about uing an overlayfs combining jffs2 and ramfs
   1659 to do upgrades that would otherwise be larger than the flash.
   1660 Could use "overlay merge" from https://github.com/kmxz/overlayfs-tools
   1661 
   1662 Wed May 17 15:18:55 BST 2023
   1663 
   1664 liminix-rebuild doesn't collect garbage (this is a mising feature, not
   1665 a bug). We think we can fix this using nix-path-registration: specifically,
   1666 by deleting anything not in it.
   1667 
   1668 What we're going to do: build a fresh system image for rotuer, then
   1669 dogfood liminix-rebuild until we've succeeded in getting it to
   1670 change its hostname
   1671 
   1672 Also wondering if we should drop outputs.default, but maybe not
   1673 
   1674 * systemConfiguration: used for updates
   1675 * vmroot: used for qemu
   1676 * flashimage: used for flashing
   1677 * tftproot: used for dev/test
   1678 
   1679 As long as we're consistently setting the default output to whichever
   1680 is the appropriate "full production image" I think we're good.
   1681 
   1682 Wed May 17 22:45:40 BST 2023
   1683 
   1684 Random thought: when we bind mount /target/persist/nix to /target/nix
   1685 we could make it read-only. worth doing?
   1686 
   1687 Thu May 18 10:59:39 BST 2023
   1688 
   1689 - liminix-rebuild can't find reboot: probably the PATH is just
   1690   generally wrong for ssh sessions (maybe all non-login sessions?)
   1691 
   1692 - need to copy path registration file somewhere useful and
   1693   delete stuff not in it at the appropriate time. Would be safest
   1694   to do that either late in the shutdown process before rebooting,
   1695   or during boot.
   1696 
   1697 Fri May 19 15:18:13 BST 2023
   1698 
   1699 If we make min-collect-garbage - just a command you can run whenever -
   1700 that will be fine for current capabilities.  It won't work with the
   1701 theoretical overlayfs system, though: we need to copy-down from the
   1702 ramfs to real flash before rebooting, and that can't happen until
   1703 there's disk space to do it
   1704 
   1705 Sat May 20 22:35:25 BST 2023
   1706 
   1707 We have a working min-collect-garbage (seems to, anyway ...)
   1708 
   1709 - having ssh host key wiped on reboot is sucky. maybe we can have
   1710 /persist/secrets and a service that looks there?
   1711 
   1712 - find out what files ash sources on non-login shell startup
   1713   [ set ENV=/etc/ashrc in parent process env ]
   1714 
   1715 - services.default is suboptimal as there is no way to add to it
   1716 without wiping it
   1717 
   1718 - decide whether to use liminix- or min- as our prefix for nixy
   1719   commands
   1720 
   1721 - should we move config.outputs  -> config.system.outputs ? see Mar 28
   1722 
   1723 - less crap firewall
   1724 
   1725 - add ipv6 support to rotuer
   1726 
   1727 - create an l2tp configuration
   1728 
   1729 - iperf and tuning
   1730 
   1731 - wlan country code
   1732 
   1733 
   1734 dropbear weak hashes? https://github.com/mkj/dropbear/issues/138
   1735 
   1736 Sun May 21 11:48:07 BST 2023
   1737 
   1738 dropbear will generate host keys on first connection. It's (probably) good that the
   1739 key is generated on-device and also that we wait until there's some randomness.
   1740 It's not so good that it will only write the key to DSS_PRIV_FILENAME which is
   1741 hardcoded to /run
   1742 
   1743 Sun May 21 17:27:31 BST 2023
   1744 
   1745 What do we need for ipv6?
   1746 
   1747 -  upgrade ppp to something with an ipv6-up-script option, move ppp and pppoe derivations into their own files
   1748 -  get ipv6 address from pppoe
   1749 -  get ipv6 delegation from DHCPv6
   1750 -  support dhcp6 in dnsmasq, and advertise prefix on lan
   1751 -  firewall settings
   1752 
   1753 Sun May 21 21:30:17 BST 2023
   1754 
   1755 Making hydra build the docs is straightforward, but making it
   1756 _publish_ the docs is outside scope, really. It can serve the files
   1757 but they're all text/plain
   1758 
   1759 Should hydra push the docs to www.liminix.org or should www.liminix.org
   1760 pull?
   1761 
   1762 TODO-at-some-point: assign uids and gids dynamically, somehow
   1763 
   1764 Tue May 23 22:56:33 BST 2023
   1765 
   1766 following the guidance at https://support.aa.net.uk/IPv6:
   1767 
   1768 we run odhcp6c to do router solicitation/advertisement dance
   1769 
   1770 
   1771 odhcp6c environment variables:
   1772 
   1773 RA_ADDRESSES=
   1774 RA_REACHABLE=0
   1775 CER=
   1776 PASSTHRU=00170020200108b0000000000000000000002020200108b0000000000000000000002021
   1777 SERVER=fe80::203:97ff:fed6:0
   1778 RA_MTU=0
   1779 RA_ROUTES=::/0,fe80::203:97ff:fed6:0,65535,512
   1780 OPTION_1=00030001e4956e4ef2fa
   1781 NTP_FQDN=
   1782 OPTION_2=00030001000397d60000
   1783 RA_DOMAINS=
   1784 DOMAINS=
   1785 AFTR=
   1786 SIP_IP=
   1787 NTP_IP=
   1788 PREFIXES=2001:8b0:de3a:40dc::/64,7198,7198
   1789 RA_HOPLIMIT=64
   1790 RA_DNS=
   1791 RDNSS=2001:8b0::2020 2001:8b0::2021
   1792 SNTP_IP=
   1793 RA_RETRANSMIT=0
   1794 SIP_DOMAIN=
   1795 ADDRESSES=2001:8b0:1111:1111:0:ffff:51bb:4cf2/128,3598,7198
   1796 
   1797 # ip -6 route |grep default
   1798 default via fe80::203:97ff:fed6:0 dev ppp0  metric 1024  expires 65211sec
   1799 
   1800 presumably from RA_ROUTES but why is the metric appaently doubled?
   1801 
   1802 Tue May 30 21:25:37 BST 2023
   1803 
   1804 We have an odhcpc script that preserves the prefix delegation from the
   1805 ISP.  We need a service that notices whenever the state is
   1806 available/has changed, and updates the LAN IPv6 address.
   1807 
   1808 The service can depend on odhcp
   1809 
   1810 add inotify to packages
   1811 use writeFennelScript with that dep
   1812 see if it works
   1813 
   1814 Wed May 31 23:33:00 BST 2023
   1815 
   1816 We have a thing that sets ipv6 address on lan interface, yay us
   1817 
   1818 A firewall would be a very good idea
   1819 
   1820 Thu Jun  1 18:46:59 BST 2023
   1821 
   1822 TODO for now:
   1823 
   1824 - services.default is suboptimal as there is no way to add to it
   1825 without wiping it
   1826 
   1827 - decide whether to use liminix- or min- as our prefix for nixy
   1828   commands
   1829 
   1830 - should we move config.outputs  -> config.system.outputs ? see Mar 28
   1831 
   1832 - less crap firewall
   1833 
   1834 - create an l2tp configuration
   1835 
   1836 - iperf and tuning
   1837 
   1838 - wlan country code
   1839 
   1840 Thu Jun  1 21:26:37 BST 2023
   1841 
   1842 how can a client machine "opt out" of using the firewall, to allow
   1843 incoming connections?  Most convenient would be to have a separate SSID
   1844 for grownups. Assuming it shows up as a separate wlan device, we can
   1845 write firewall rules to allow incoming connections on that interface
   1846 (can we? only if the packet is identifiable as destined for that interface)
   1847 
   1848 https://www.rfc-editor.org/rfc/rfc6092.html
   1849 https://emailstuff.org/rfc/rfc7084
   1850 
   1851 We could block incoming for slaac and dhcp addresses and permit it for
   1852 stable private addresses. If we were fairly sure that devices won't
   1853 ask for stable private addresses just for funsies.
   1854 
   1855 https://wiki.archlinux.org/title/IPv6_#Stable_private_addresses
   1856 
   1857 
   1858 
   1859 Fri Jun  2 14:42:43 BST 2023
   1860 
   1861 I found a handy guide to nftables at https://ww.telent.net/2023/6/2/turning_the_nftables
   1862 
   1863 Mon Jun  5 16:56:44 BST 2023
   1864 
   1865 
   1866 How are we going to do this firewall thing then?
   1867 I can see no reason to have more than one table per family, so lets
   1868 just name the tables after families
   1869 
   1870 There is nothing in nftables for functionally grouping rules by
   1871 requirement that may touch multiple hooks/chains, so we need our own
   1872 abstraction - and we can't call it any name that nftables uses already
   1873 (so, not "ruleset"). rulegroup?
   1874 
   1875 "policy" would be a good name except that it's already taken
   1876 
   1877 "concern"? "requirement"? "feature"?
   1878 
   1879 Mon Jun 19 20:45:48 BST 2023
   1880 
   1881 why is chrony using libedit?
   1882 
   1883 Thu Jun 22 09:52:57 BST 2023
   1884 
   1885 - There is a lot more lua being installed (luac, docs, static
   1886   libraries etc) than we really need.
   1887 
   1888 - update User docs to include a list of supported  targets
   1889 
   1890 Thu Jun 22 23:43:06 BST 2023
   1891 
   1892 - is there a sysfs to enable ipv6 forwarding?
   1893 - we haven't an ipv4 firewall yet
   1894 
   1895 
   1896 PATH=`echo /nix/store/*nftables*/bin`:$PATH
   1897 nft list ruleset
   1898 
   1899 Thu Jun 22 23:58:58 BST 2023
   1900 
   1901 Looks like we're missing at least one kernel config setting for
   1902 nftables. Would this be a good time to do a derivation for building
   1903 kernel modules?
   1904 
   1905 
   1906 Sun Jul  9 21:21:17 BST 2023
   1907 
   1908 
   1909 Tue Jul 11 22:10:17 BST 2023
   1910 
   1911 - s6 cheatsheet, find or write
   1912 - could we have > 1 module add to services.default?
   1913 - odhcp should parse values from environ and write more files, to save readers
   1914  from parsing it
   1915 - pkgs.liminix, who knows what thats for any more?
   1916 - interface.device, as a  general rule, doesn't work because the
   1917   device name may be known only at runtime (e.g. for ppp)
   1918 - iperf
   1919 - figure out wifi regdomain
   1920 
   1921 Tue Jul 11 23:01:59 BST 2023
   1922 
   1923 We can make services depend on kernel modules, however not on bakedin
   1924 kernel config
   1925 
   1926 [from March: "Let's think about services and modules."]
   1927 
   1928 Module
   1929 + can change global config
   1930   * add users, groups etc
   1931   * change kernel config
   1932   * change busybox config
   1933 + well-typed parameters
   1934 - is a "singleton": can't have the same module included twice
   1935   with different config. e.g. can't have two hostap modules running on
   1936   different wlan radios.
   1937 - can't express dependencies: a depends on b
   1938 
   1939 thought I had then was: modules provide services. requiring the
   1940 ppp module causes config.services.ppp to exist, so you can
   1941 
   1942 services.default = [
   1943   (config.services.ppp {
   1944     tty = "17";
   1945     baud = "57600";
   1946     secrets = blah;
   1947     })
   1948   ...
   1949 ]
   1950 
   1951 this might work. also though we should find out how to do type checking on
   1952 service params
   1953 
   1954 Wed Jul 12 23:23:02 BST 2023
   1955 
   1956 https://github.com/NixOS/mobile-nixos/pull/406 // why mobile nixos uses
   1957 mobile.outputs instead of system.build
   1958 
   1959   suggests that system.build may not be a thing to blindly emulate
   1960 
   1961 if a service is a derivation should we expect to want to be able to call
   1962 it with .override? maybe we want to override the package containing the
   1963 daemon it runs. How do we best pass service config as well?
   1964 
   1965 Maybe a service template is a function that returns a derivation
   1966 
   1967 
   1968 imports = [ ./modules/pqmud.nix ];
   1969 services.mud = system.services.pqmud {
   1970   realm = "A deep cavern";
   1971   port = 4067;
   1972   users = import ./allowed-users.nix;
   1973   # etc etc
   1974 };
   1975 services.mudBeta = let mud =
   1976   system.services.pqmud {
   1977     realm = "A very deep cavern";
   1978     port = 4068;
   1979     users = import ./allowed-users.nix;
   1980   };
   1981   in mud.overrideAttrs { pqmud = pkgs.pkmudLatest; };
   1982 
   1983 so we have
   1984 
   1985 config.system.services # services provided by modules
   1986 config.system.outputs  # build artefacts of various types
   1987 
   1988 the services provided by a module must be introspectable in some way
   1989 so that we can compile a list of service options per module
   1990 
   1991 service parameters are defined using the module type system.
   1992 Something like this?
   1993 
   1994 # mud.nix
   1995 
   1996 system.services.pqmud = args :
   1997   let t = {
   1998     name = mkOption { type = types.str; };
   1999     realm = mkOption { type = types.str; };
   2000     port = mkOption { type = types.port; default = 12345; };
   2001     users = mkOption { type = types.any; };
   2002   };
   2003   in assert isType (submodule { options = t; }) args; longrun {
   2004      inherit (args) name;
   2005      run = "${pkgs.pqmud}/bin/pqmud --port ${port} ....."
   2006   };
   2007 
   2008 Fri Jul 14 19:07:59 BST 2023
   2009 
   2010 It works for pppoe, though typechecking error messages could be
   2011 better.
   2012 
   2013 - We need to find a good place to keep the typeCheck function so that
   2014 everyone can use it.
   2015 
   2016 - also the type_service type defn exists only locally in modules.nix,
   2017 and we would like to refer to it elsewhere
   2018 
   2019 Thu Aug 10 21:46:36 BST 2023
   2020 
   2021 to finish service/modules milestone
   2022 
   2023 [done] there are some modules not using serviceDefn
   2024 - modules included by standard.nix should have all their options
   2025   grouped together in docs
   2026   how can we determine which they are? or maybe "modules that
   2027    don't contain services" is an acceptable criterion
   2028   maybe this is not actually an issue, if the modules are
   2029    reasonably coherent. It looks odd now because base.nix is a mess
   2030 [done] print the module pathname so people know what to import
   2031 [done] docs don't print the examples
   2032 [check?] and seem to be getting the default wrong too
   2033 - decide what we deem to be "internal" (if anything)
   2034    is `filesystem` internal, for example? or `busybox`? they're
   2035    both mostly _used_ internally but may still be valuable to expose
   2036 [done] maybe document outputs separately or not at all?
   2037 [done] bridge to be one service instead of two?
   2038 [done] get rid of services/
   2039 - anything else in rotuer.nix that we should servicify
   2040 - services for liminix.networking
   2041 - a nice way to specify service dependencies
   2042 [done] - do another video
   2043 
   2044 Mon Aug 21 20:02:55 BST 2023
   2045 
   2046 a nice way to do dependencies would be somethng like
   2047 
   2048 services.thething =
   2049   let s = svc.thing { .... };
   2050   in addDependencies s (with config.services; [otherthing yetanother]);
   2051 
   2052 except that addDependencies is a really klunky name. dependsOn is very
   2053 slightly better? or maybe it could be a function of the derivation?
   2054 
   2055 services.thething =
   2056   svc.thing { .... }.depends (with config.services; [otherthing yetanother]);
   2057 
   2058 ---
   2059 
   2060 what does it mean to be dependent on an interface? that's it up? running?
   2061 has an address? has a collection of addresses?
   2062 
   2063 
   2064   services.defaultroute4 = route {
   2065     name = "defaultroute4";
   2066     via = "$(output ${services.wan} address)";
   2067     target = "default";
   2068     dependencies = [ services.wan ];
   2069   };
   2070 
   2071 - this route requires the interface to have an address (if wan is an
   2072   interface, anyway ...)
   2073 
   2074 - but otoh a dhcp client doesn't want to wait for an address, because
   2075    it is assigning the address.
   2076 
   2077 should an address provider have "interface name" as an output?
   2078 is there a set of outputs that every address provider should have -
   2079 whether static, dhcp, pppoe?
   2080 
   2081 maybe we're in decision paralysis and should just move forward with
   2082 what we know
   2083 
   2084 Wed Aug 23 18:56:08 BST 2023
   2085 
   2086 We may want to change the hardware device files to specify network
   2087 interface names not services. Otherwise hardware devices (boards)
   2088 depend on module-based-services, which is a bit weird.
   2089 
   2090 Thu Aug 24 18:54:03 BST 2023
   2091 
   2092 - we want network and bridge to be separate modules, because bridge
   2093 introduces extra kernel config
   2094 
   2095 - bridge/service wants to create a network device ("ip link"),
   2096 using quite similar code as network/link.nix
   2097 
   2098 - but bridge/service is a derivation: it has sight of pkgs but not
   2099 config
   2100 
   2101 offtopic: useful s6-rc commands at https://www.skarnet.org/software/s6-rc/faq.html
   2102 
   2103 Fri Aug 25 23:37:57 BST 2023
   2104 
   2105 where we left off: bridge is a bundle, and bundles can't have outputs,
   2106 so how do we set the ifname of the bridge?
   2107 
   2108 - ifname of the primary is set
   2109 - actually, most things that depend on the bridge really just depend
   2110   on the primary anyway (it's OK if 1 <= n < #members are down)
   2111 - but *something* should depeond on all the members
   2112 
   2113 turns out maybe we needed two services after all?
   2114 
   2115 Sun Aug 27 23:50:18 BST 2023
   2116 
   2117 I've done enough to make rotuer build, but in the process
   2118 trashed vanilla-configuration as I entirely forgot we don't have
   2119 a dhcpv4 client service. Need to fix that ...
   2120 
   2121 - anything else in rotuer.nix that we should servicify
   2122 - anything in vanilla-configuration ditto
   2123 - and arhcive (rsync, watchdog)
   2124 - services for liminix.networking
   2125 - tidy up the dependency handling in serviceDefn build
   2126    (interface is fine, implementation is a bit brutal)
   2127 - write a blog entry
   2128 
   2129 Mon Aug 28 16:58:49 BST 2023
   2130 
   2131 - [done] ntp is not setting the time
   2132 - nftables syntax error
   2133 
   2134 Thu Aug 31 23:53:54 BST 2023
   2135 
   2136 - anything else in rotuer.nix that we should servicify
   2137  [done] - packet forwarding
   2138   - dhcp6 client
   2139   - what to do with acquire-{wan,lan} scripts?
   2140   - resolvconf
   2141 - [done] anything in vanilla-configuration ditto
   2142   - packet forwarding
   2143 - and arhcive
   2144   - [not doing] rsync
   2145   - [done] watchdog
   2146   - [done] mount
   2147 - nftables syntax error
   2148 - tidy up the dependency handling in serviceDefn build
   2149    (interface is fine, implementation is a bit brutal)
   2150 - [done] services for liminix.networking
   2151 - [done] write a blog entry
   2152 - [done] ntp is not setting the time
   2153 - [done] static dhcp(6) lease support reqd for dogfooding
   2154 
   2155 Sat Sep  2 21:35:41 BST 2023
   2156 
   2157 Considerations for "mount" service: each filesystem needs to depend on
   2158 any mount points for its parent directories, and maybe also on other
   2159 services (e.g. filesystem modules, network devices, routes)
   2160 
   2161 mountpoints = {
   2162  mnt = {
   2163    media = svc.mountpoint.build {
   2164      fstype = "msdos";
   2165      device = "/dev/sda1";
   2166      options = [ ...];
   2167    };
   2168    archive = svc.mountpoint.build {
   2169      fstype = "ext4";
   2170      device = "/dev/sda2";
   2171      options = [ ...];
   2172      mountpoints = {
   2173        remote = svc.mountpoint.build {
   2174          fstype = "nfs";
   2175 	 device = "doc.ic.ac.uk:/public";
   2176        };
   2177      };
   2178    };
   2179   };
   2180 }
   2181 
   2182 services.somethingelse = svc.ftpd.build {
   2183   # ...
   2184   dependencies = [ mountpoints.mnt.archive ];
   2185 }
   2186 
   2187 what don't we like about this? we have to walk the nested attrset in a
   2188 weird way, because the services may contain other mountpoints. Maybe
   2189 just keep it simple and do
   2190 
   2191 
   2192 services.mountpoints = bundle {
   2193  name = "mountpoints";
   2194  contents = [
   2195    svc.mountpoint.build {
   2196      device = "/dev/sda2"; fstype = "ext4"; directory = "/mnt/isos";
   2197    };
   2198    svc.mountpoint.build {
   2199      device = "/dev/sdb1"; fstype = "msdos"; directory = "/mnt/backup";
   2200      dependencies = [ load-vfat-module ];
   2201    };
   2202  ];
   2203 }
   2204 
   2205 Sun Sep  3 17:34:36 BST 2023
   2206 
   2207 how to dogfood
   2208 
   2209 DHCP6 server: static lease support
   2210 DHCP client and acquire-{lan-prefix,wan-address}
   2211 
   2212 The emergency boot thingy in glinet u-boot won't help because it
   2213 expects to flash from its tftp request instead of booting it. So we
   2214 could use kexec instead except that the openwrt install doesn't have
   2215 it.  So we could swap the hardware devices, the only downside of that
   2216 being that then I don't have a test system any more. Or we could YOLO it.
   2217 
   2218 Sun Sep  3 22:11:02 BST 2023
   2219 
   2220 I think we should rejigger the documentation ...
   2221 
   2222 - "getting started": worked example, building and installing Liminix
   2223 with a very simple config (wifi AP with ssh daemon)
   2224 
   2225 - using modules
   2226   - link to module reference
   2227 
   2228 - creating custom services
   2229   - longrun or oneshot
   2230   - dependencies
   2231   - outputs
   2232 
   2233 - creating your own modules
   2234 
   2235 - hacking on Liminix itself
   2236 
   2237 - contributing
   2238 
   2239 - external links and resources
   2240 
   2241 - module reference
   2242 
   2243 - hardware device reference
   2244 
   2245 ---
   2246 
   2247 I think we might rename wlan_24 to wlan and wlan_5 to wlan1.
   2248 This is on the assumption that almost no device is 5GHz only, so
   2249 would make it easier to write a basic wlan example that works
   2250 both on 2.4GHz boards and dual radio boards
   2251 
   2252 Mon Sep  4 23:15:26 BST 2023
   2253 
   2254 If dhcpcd parsed the update-script output into separate files, half
   2255 the complexity of acquire-lan-prefix would go away. The other half is
   2256 because it subscribes to changes in the outputs instead of just
   2257 running once. Perhaps there's a better way to do that?
   2258 
   2259 Could separate prefixes and addresses something like this...
   2260 
   2261 outputs/prefix/2001\:8b0\:de3a\:40dc\:\:/prefix
   2262 outputs/prefix/2001\:8b0\:de3a\:40dc\:\:/length
   2263 outputs/prefix/2001\:8b0\:de3a\:40dc\:\:/preferred
   2264 outputs/prefix/2001\:8b0\:de3a\:40dc\:\:/valid
   2265 outputs/prefix/2001\:8b0\:de3a\:80\:\:/prefix
   2266 outputs/prefix/2001\:8b0\:de3a\:80\:\:/length
   2267 outputs/prefix/2001\:8b0\:de3a\:80\:\:/preferred
   2268 outputs/prefix/2001\:8b0\:de3a\:80\:\:/valid
   2269 
   2270 the directory name is arbitrary as long as it's unique. Might even be better to
   2271 remove the colons
   2272 
   2273 outputs/prefix/200108b0de3a40dc/valid
   2274 
   2275 or we could adopt the MS convention and replace with hyphens
   2276 
   2277 outputs/prefix/2001-8b0-de3a-40dc--/prefix
   2278 
   2279 Also: we should write some kind of test for this...
   2280 
   2281 
   2282 Tue Sep  5 21:36:39 BST 2023
   2283 
   2284 How do we set the cpu governor?
   2285 
   2286 
   2287 Fri Sep  8 21:26:36 BST 2023
   2288 
   2289 We want a fennel thing that reads a filesystem tree into a nested
   2290 table. And a thing to diff two tables
   2291 
   2292 Sat Sep  9 22:40:50 BST 2023
   2293 
   2294 Subscribers to odhcp6c outputs need to be able to tell which addresses
   2295 are new and which have been removed since the last run, which now we
   2296 have ohdcp-script  producing parsed data means they need to compare
   2297 tables by value. Which is a faff.
   2298 
   2299 What if the directory name were a hash of all the relevant fields
   2300 such that clients could just say "new directory, must be new address"
   2301 
   2302 We can have literal prefix, then need to encode
   2303 length,preferred,valid,extra space-efficiently. I cannot currently see
   2304 any way to use whatever hashing Lua uses for its table lookups,
   2305 which is a bit disapppointing, so we might have to make our own
   2306 
   2307 
   2308 https://gist.github.com/scheler/26a942d34fb5576a68c111b05ac3fabe
   2309 this is DJBHash, though doesn't appear to deal with integer overflow
   2310 
   2311 
   2312 function hash(str)
   2313     h = 5381;
   2314 
   2315     for c in str:gmatch"." do
   2316         h = ((h << 5) + h) + string.byte(c)
   2317     end
   2318     return h
   2319 end
   2320 
   2321 
   2322 Mon Sep 11 20:31:25 BST 2023
   2323 
   2324 acquire-lan/wan-foo have no tests, and the test setup is a bit of a
   2325 faff as they are both waiting on the filesystem
   2326 
   2327 also, testing lua scripts is a faff without splitting them into
   2328 script/module
   2329 
   2330 am wondering if we could do some kind of convention that we only write
   2331 modules not scripts but something in the fennel->lua can call the
   2332 module's `run` method.
   2333 
   2334 Tuesday
   2335 
   2336 Here is a working shebang for write-fennel:
   2337 
   2338 #!/nix/store/5iwv3h2jjbk2vib2bpwx3g9knpb02x3y-lua-5.3.6/bin/lua -e dofile(arg[0]).run()
   2339 
   2340 Tue Sep 12 20:47:52 BST 2023
   2341 
   2342 We don't handle unbound or stopped states in odhcp consumers. I think
   2343 probably we should do this in odhcp-script by deleting the outputs,
   2344 rather than making each consumer do it.
   2345 
   2346 ... turns out that odhcp6c itself unsets ADDRESSES and PREFIXES before
   2347 calling the script with "unbound", so maybe we don't need to do
   2348 anything special.
   2349 
   2350 Wed Sep 13 17:55:33 BST 2023
   2351 
   2352 
   2353 
   2354 @400000000000001f2723b3cb eth1.link.pppoe Script /nix/store/nyks8zl86dcp44k5sjcc76digrnfgm17-ip-up finished (pid 403), status = 0x0
   2355 @400000000000001f27b2db3b eth1.link.pppoe Script /nix/store/ds0lc4qd1zfiyxsva87rpplyr21awjh1-ip6-up finished (pid 404), status = 0x1
   2356 
   2357 @400000000000001f30a7c5c5 /nix/store/v9ijgyywizqbbd9y73r2wifkxc0d1jjm-route-default-1a22c69d0e1f-up: line 4: input: not found
   2358 @400000000000001f31abf9b5 ip: command line is not complete, try "help"
   2359 @400000000000001f31ca1395 s6-rc: warning: unable to start service route-default-1a22c69d0e1f: command exited 1
   2360 @400000000000001f31f236b4 s6-rc: info: service route-default-d2586cf00da0 successfully started
   2361 @
   2362 
   2363 
   2364 Wed Sep 13 18:05:38 BST 2023
   2365 
   2366 TODO
   2367 
   2368 - service for dhcp6 client
   2369 - move acquire-{wan,lan} scripts out of examples/
   2370 - service for resolvconf
   2371 - nftables syntax error
   2372 - tidy up the dependency handling in serviceDefn build
   2373    (interface is fine, implementation is a bit brutal)
   2374 - docs
   2375 
   2376 considerations:
   2377 
   2378 1) in some ways, we should be able to specify acquire-{wan,lan} as if
   2379 they were just additional addresses on the respective
   2380 interfaces. However, they're longruns so the implementation of
   2381 "address" doesn't really fit.
   2382 
   2383 2) should they be bundled into a dhcp client service? I think the
   2384 answer is "no" because which of the dhcp config we want to
   2385 honour locally (and how) is policy not mechainmsm
   2386 
   2387 svc.dhcp6c.client.build { interface = wan; };
   2388 svc.dhcp6c.address.build {
   2389   inherit client;
   2390   interface = lan;
   2391 };
   2392 svc.dhcp6c.address.build {
   2393   inherit client;
   2394   interface = wan;
   2395 };
   2396 svc.dhcp6c.prefix.build {
   2397   inherit client;
   2398   interface = lan;
   2399   index = 1;			# default to first interface
   2400 };
   2401 svc.dhcp6c.prefix.build {
   2402   inherit client;
   2403   interface = vpn;
   2404   index = 2;
   2405 };
   2406 
   2407 
   2408 
   2409 Fri Sep 15 12:04:25 BST 2023
   2410 
   2411 Qemu worked example provides dhcp and ssh service
   2412 
   2413 Hardware worked example needs to be plugged into same lan as build
   2414 machine if we are going to tftp the image onto it - so it might be
   2415 awkward if we run dhcp on it
   2416 
   2417 The device I have lying around is the A
   2418 
   2419 How do we do the actual flash step? Assuming the device is running
   2420 stock firmware, from a laptop we can wifi to it and use the web ui to
   2421 upgrade
   2422 
   2423 we can't build the hellonet config because it requires tftp
   2424 
   2425 plug in mt300a
   2426 put stock firmware on it
   2427 
   2428 Sun Sep 17 00:08:03 BST 2023
   2429 
   2430 I don't think the user manual needs a full justification of why we
   2431 have the module/service split. Maybe we should have "decision records"
   2432 in the git tree instead
   2433 
   2434 Sun Sep 17 16:44:31 BST 2023
   2435 
   2436 Can we figure out which bits of the old doc are missing from the new
   2437 one and just transplant those? Then we can merge it sooner
   2438 instead of blocking on writig all the new stuff
   2439 
   2440 Mon Sep 25 16:58:51 BST 2023
   2441 
   2442 jffs2 on mt300a isn't finding root partition in initramfs, and it
   2443 seems to be because MTD_SPLIT_UIMAGE_FW isn't working
   2444 
   2445 [    0.426792] spi spi0.0: force spi mode3
   2446 [    0.431305] spi-nor spi0.0: w25q128 (16384 Kbytes)
   2447 [    0.436322] 5 fixed-partitions partitions found on MTD device spi0.0
   2448 [    0.442875] OF: Bad cell count for /palmbus@10000000/spi@b00/flash@0/partitions
   2449 [    0.450400] OF: Bad cell count for /palmbus@10000000/spi@b00/flash@0/partitions
   2450 [    0.458208] OF: Bad cell count for /palmbus@10000000/spi@b00/flash@0/partitions
   2451 [    0.465751] OF: Bad cell count for /palmbus@10000000/spi@b00/flash@0/partitions
   2452 [    0.473522] Creating 5 MTD partitions on "spi0.0":
   2453 [    0.478466] 0x000000000000-0x000000030000 : "u-boot"
   2454 [    0.484447] 0x000000030000-0x000000040000 : "u-boot-env"
   2455 [    0.490888] 0x000000040000-0x000000050000 : "factory"
   2456 [    0.497110] 0x000000050000-0x000000fd0000 : "firmware"
   2457 [    0.596423] 0x000000ff0000-0x000001000000 : "art"
   2458 [    0.611508] gsw: setting port4 to ephy mode
   2459 
   2460 with squashfs root it's the same but for the extra split partitions:
   2461 
   2462 [    0.468715] Creating 5 MTD partitions on "spi0.0":
   2463 [    0.473653] 0x000000000000-0x000000030000 : "u-boot"
   2464 [    0.479652] 0x000000030000-0x000000040000 : "u-boot-env"
   2465 [    0.486085] 0x000000040000-0x000000050000 : "factory"
   2466 [    0.492318] 0x000000050000-0x000000fd0000 : "firmware"
   2467 [    0.499304] 2 uimage-fw partitions found on MTD device firmware
   2468 [    0.505457] Creating 2 MTD partitions on "firmware":
   2469 [    0.510543] 0x000000000000-0x000000260000 : "kernel"
   2470 [    0.516616] 0x000000260000-0x000000f80000 : "rootfs"
   2471 [    0.522570] mtd: device 5 (rootfs) set to be root filesystem
   2472 [    0.528565] 0x000000ff0000-0x000001000000 : "art"
   2473 
   2474 turns out this is because the device thinks it has 4k erase block size
   2475 because MTD_SPI_NOR_USE_4K_SECTORS was set, and that was causing
   2476 mtdsplit to look in the wrong place for a root filesystem
   2477 
   2478 Mon Sep 25 18:50:05 BST 2023
   2479 
   2480 No, that wasn't it. Turned out to be an endianness-dependent check for
   2481 JFFS2 magic in mtdsplit.
   2482 
   2483 setenv serverip 10.0.0.1
   2484 setenv ipaddr 10.0.0.8
   2485 tftp 0xa00000 result/uimage
   2486 bootm 0xa00000
   2487 
   2488 Fri Sep 29 20:50:39 BST 2023
   2489 
   2490 setenv bootargs 'liminix mtdparts=phram0:M(rootfs) phram.phram=phram0,0x40411f28,4194304,65536 memmap=4194304$0x40411f28 root=/dev/mtdblock0 console=ttyAMA0,115200 earlycon'
   2491 
   2492 setenv serverip 10.0.0.1
   2493 setenv ipaddr 10.0.0.5
   2494 setenv bootargs 'liminix console=ttyS0,115200  panic=10 oops=panic earlycon=uart8250,mmio32,0x11002000 root=/dev/mtdblock0'
   2495 tftp 0x4007ff28 result/uimage ;  tftp 0x40432f28 result/rootfs
   2496 bootm 0x4007ff28
   2497 
   2498 setenv bootargs 'liminix console=ttyS0,115200  panic=1 oops=panic earlycon  root=/dev/mtdblock0'
   2499 
   2500 md 0x42ff0000
   2501 
   2502 Cannot find regmap for /infracfg@10000000: -524.
   2503 
   2504 # "console=ttyAMA0,38400 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/mtdblock0 rootfstype=squashfs fw_devlink=off"
   2505 
   2506 
   2507 40812468: 69726553 203a6c61 41424d41 304c5020    Serial: AMBA PL0
   2508 40812478: 55203131 20545241 76697264 3c0a7265    11 UART driver.<
   2509 40812488: 61723e33 706f6f6d 61203a73 6165726c    3>ramoops: alrea
   2510 40812498: 69207964 6974696e 7a696c61 3c0a6465    dy initialized.<
   2511 408124a8: 61723e34 706f6f6d 70203a73 65626f72    4>ramoops: probe
   2512 408124b8: 20666f20 66663234 30303030 6d61722e     of 42ff0000.ram
   2513 408124c8: 73706f6f 69616620 2064656c 68746977    oops failed with
   2514 408124d8: 72726520 2d20726f 3c0a3232 61433e33     error -22.<3>Ca
   2515 408124e8: 746f6e6e 6e696620 65722064 70616d67    nnot find regmap
   2516 408124f8: 726f6620 6e692f20 63617266 31406766     for /infracfg@1
   2517 40812508: 30303030 3a303030 32352d20 333c0a34    0000000: -524.<3
   2518 40812518: 6e61433e 20746f6e 646e6966 67657220    >Cannot find reg
   2519 MT7622>
   2520 40812528: 2070616d 20726f66 666e692f 66636172    map for /infracf
   2521 40812538: 30314067 30303030 203a3030 3432352d    g@10000000: -524
   2522 40812548: 3e333c0a 6e6e6143 6620746f 20646e69    .<3>Cannot find
   2523 40812558: 6d676572 66207061 2f20726f 72666e69    regmap for /infr
   2524 40812568: 67666361 30303140 30303030 2d203a30    acfg@10000000: -
   2525 40812578: 0a343235 433e333c 6f6e6e61 69662074    524.<3>Cannot fi
   2526 40812588: 7220646e 616d6765 6f662070 702f2072    nd regmap for /p
   2527 40812598: 63697265 31406766 32303030 3a303030    ericfg@10002000:
   2528 408125a8: 32352d20 313c0a34 616e553e 20656c62     -524.<1>Unable
   2529 408125b8: 68206f74 6c646e61 656b2065 6c656e72    to handle kernel
   2530 408125c8: 67617020 20676e69 75716572 20747365     paging request
   2531 408125d8: 76207461 75747269 61206c61 65726464    at virtual addre
   2532 408125e8: 66207373 66666666 66666666 66666666    ss fffffffffffff
   2533 408125f8: 0a656666 4d3e313c 61206d65 74726f62    ffe.<1>Mem abort
   2534 
   2535 
   2536 CONFIG_SERIAL_8250_FSL=y
   2537 CONFIG_SERIAL_8250_MT6577=y
   2538 CONFIG_SERIAL_8250_NR_UARTS=3
   2539 CONFIG_SERIAL_8250_RUNTIME_UARTS=3
   2540 CONFIG_SERIAL_DEV_BUS=y
   2541 CONFIG_SERIAL_DEV_CTRL_TTYPORT=y
   2542 CONFIG_SERIAL_MCTRL_GPIO=y
   2543 CONFIG_SERIAL_OF_PLATFORM=y
   2544 
   2545 Mon Oct  2 10:17:04 BST 2023
   2546 
   2547 We have a bootable aarch64 kernel for the Belkin, but it does not
   2548 understand the memmap= parameter we're using to protect the
   2549 phram image from being used as general memory.
   2550 
   2551 One option is to add a reserved-memory stanza in the device tree,
   2552 using u-boot "fdt" command, but we don't know the fdt address in u-boot
   2553 because it doesn't have any commands to parse the image and set
   2554 variables pointing at the sub-components. (There's iminfo, but it's
   2555 onyl human-readable)
   2556 
   2557 Second option is to amend the dtb in the tftpboot module: this
   2558 would mean regenerating the uimage
   2559 
   2560 Third option: for tftpboot do we _have_ to use FIT? maybe we could
   2561 grab the fdt as a separate tftp transaction
   2562 
   2563 we need to apply kernel patch 9401911f2d9f89035f7acebab16e72d43d1282fb
   2564 to avoid using ioremap on sysem ram which is not allowed on arm
   2565 
   2566 
   2567 Tue Oct  3 14:15:38 BST 2023
   2568 
   2569 Progress on Liminix ARM support. The device I'm starting with is
   2570 the Belkin RT3200 (also known as [Linksys E8450](https://openwrt.org/toh/linksys/e8450)) which seems to be a featureful piece of kit, and whioch I snagged for a
   2571 very good price on the Bay of E
   2572 
   2573 # Where are we right now?
   2574 
   2575 * we can TFTP boot it to userland
   2576 * ethernet works
   2577 
   2578 ## What else needs doing?
   2579 
   2580 * it has dual band wifi with many interesting features. I've built the
   2581 
   2582 * we're only running in RAM, probably need to add some kernel config
   2583   to support the flash
   2584 * initramfs support is not yet implemented
   2585 * the flash is NAND flash and it's quite large compared with the
   2586   existing Liminix devices, so we're going to add UBIFS which will
   2587   use it better than  JFFS2 does
   2588 * all this work is on a branch and needs to be cleaned up a lot before
   2589    I'm letting it into main
   2590 
   2591 ## What have we found?
   2592 
   2593 There are some significant differences between this and the MIPS
   2594 devices (yes, other than an entirely different architecture), mostly
   2595 to do with "legacy boot" support or the lack thereof. For example:
   2596 
   2597 * there aren't any options like `MIPS_RAW_APPENDED_DTB` to glom
   2598   together a kernel and device tree (FDT), because the bootloader is
   2599   expected to be able to provide a FDT following "standards".
   2600   U-Boot will do this, provided that we use the newer "FIT" Uimage
   2601   format which allows a kernel and DTB and initrd to be combined in
   2602   the same container.  (Sadly we can't use FIT everywhere because a
   2603   lot of MIPS devices use really old forks of U-Boot that don't
   2604   understand it)
   2605 
   2606 * for tftpboot, on MIPS we use the `memmap` kernel command line option
   2607   to reserve some RAM for the root filesystem. On Arm there's no such
   2608   option, so we have to add a
   2609   [reserved-memory](https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/reserved-memory/reserved-memory.yaml)
   2610   node in the device tree instead. Which means, given that we _only_
   2611   want to do this when tftp booting (the memory is wasted
   2612   otherwise), we have to rewrite the device tree in that
   2613   scenario.
   2614 
   2615 * then it turns out that phram doesn't (didn't) work anyway, because
   2616   it calls ioremap() and [you can't use ioremap on system memory on ARM](https://lwn.net/Articles/409689/). In newer kernels this is
   2617   fixed: there is a [conditional](https://github.com/torvalds/linux/blob/master/drivers/mtd/devices/phram.c#L127) here to use whichever of ioremap or
   2618   memremap is appropriate for the memory passed to phram, but it looks
   2619   non-trivial to backport so I've gone for a [much less sophisticated approach](https://gti.telent.net/dan/liminix/commit/f7cd9c2b6e6c99a228e066b09e3febcf71c63fa1#diff-d8e355f1b2dcde7378ebb40c92cdd2ce3125753c)
   2620 
   2621 * we're using [DSA](https://www.kernel.org/doc/Documentation/networking/dsa/dsa.txt) instead of the OpenWrt [swconfig](https://openwrt.org/docs/techref/swconfig) program. There was actually surprisingly little work needed to adjust to this.
   2622 
   2623 
   2624 Other than that, it was mostly the usual process of "did the kernel
   2625 crash silently, or has it just been unable to open a console device?".
   2626 In this regard, *one neat trick*: even though U-Boot on this device
   2627 doesn't support pstore, we can use it anyway if we don't do compression.
   2628 Enable
   2629 
   2630 ```
   2631         PSTORE = "y";
   2632         PSTORE_RAM = "y";
   2633         PSTORE_CONSOLE = "y";
   2634         PSTORE_DEFLATE_COMPRESS = "n";
   2635 ```
   2636 
   2637 then boot with `panic=3 oops=panic`, then when it resets use the
   2638 U_Boot `md` command to see what happened:
   2639 
   2640 ```
   2641 MT7622> md 0x42ff0000
   2642 42ff0000: 43474244 00000000 00000ff4 3d3d3d3d    DBGC........====
   2643 42ff0010: 39342e31 36373031 500a442d 63696e61    1.491076-D.Panic
   2644 42ff0020: 50203123 31747261 3e363c0a 20505050    #1 Part1.<6>PPP
   2645 42ff0030: 20445342 706d6f43 73736572 206e6f69    BSD Compression
   2646 [....]
   2647 42ff0ca0: 20676e69 73756e75 6b206465 656e7265    ing unused kerne
   2648 42ff0cb0: 656d206c 79726f6d 3731203a 0a4b3832    l memory: 1728K.
   2649 42ff0cc0: 523e363c 2f206e75 74696e69 20736120    <6>Run /init as
   2650 42ff0cd0: 74696e69 6f727020 73736563 3e373c0a    init process.<7>
   2651 ```
   2652 
   2653 Wed Oct  4 21:08:44 BST 2023
   2654 
   2655 By randomly including chinks of the openwrt config we have made it
   2656 find the mt7915e on the pcie bus. I just don't yet know which bit of
   2657 the openwrt config it was.
   2658 
   2659 It doesn't actually work yet though. 5GHz wifi gets calibration data
   2660 from the flash, so it is not going to work unless (1) we reflash the
   2661 firmware partition, or (2) we find another way to provide it
   2662 calibration data.
   2663 
   2664 https://forum.openwrt.org/t/belkin-rt3200-linksys-e8450-wifi-ax-discussion/94302/401
   2665 
   2666 Sat Oct  7 22:56:40 BST 2023
   2667 
   2668 We're almost ready to merge the rt3200 support (it's not finished
   2669 but it mostly won't break mips) except for the uimage module
   2670 which needs all that FIT stuff, and the tftpboot contortions
   2671 to amend the dtb for memmap
   2672 
   2673 For legacy uimage
   2674 
   2675 1) add commandline params to dtb
   2676 2) objcopy fdt into vmlinux.elf
   2677 3) strip to raw image and compress
   2678 4) mkimage
   2679 
   2680 
   2681 For FIT uimage
   2682 
   2683 1) add commandline params to dtb
   2684 2) strip to raw image and compress
   2685 3) create its file
   2686 4) mkimage
   2687 
   2688 Do we still want to handle the no-dtb case? what about
   2689 standards-compliant boot, where u-boot is providing the dtb? No option
   2690 to provide a commandline in that case, but maybe also no need to.
   2691 
   2692 For tftpboot, am undecided. We could use the dtb rewriting thing
   2693 everywhere, in the interest of consistency.
   2694 
   2695 Mon Oct  9 20:45:54 BST 2023
   2696 
   2697 we bumped the kernel entry point to the 32MB mark, as
   2698 
   2699 (1) when using jffs2 (big rootfs image) it was clobbering the dtb at
   2700 the end of the filesystem
   2701 
   2702 (2) it should be 2MB aligned anyway and wasn't
   2703 
   2704 However, this has given us the next problem:
   2705 
   2706 OF: fdt: Reserved memory: failed to reserve memory for node 'secmon@43000000': base 0x00000000430B
   2707 OF: reserved mem: OVERLAP DETECTED!
   2708 phram-rootfs (0x0000000040400000--0x0000000053a31488) overlaps with ramoops@42ff0000 (0x000000004)
   2709 Zone ranges:
   2710   DMA      [mem 0x0000000040000000-0x000000005fffffff]
   2711   DMA32    empty
   2712   Normal   empty
   2713 Movable zone start for each node
   2714 
   2715 the end of that phram-rootfs region looks well sus.
   2716 
   2717 [ turns out that decimal is not hex ]
   2718 
   2719 Tue Oct 10 21:37:31 BST 2023
   2720 
   2721 UBI bleurgh ...
   2722 
   2723 The DTB for this device, and/or the OpenWrt installer,  seems to
   2724 expect already that mtd4 is a UBI thing
   2725 
   2726 mtdinfo -a says:
   2727 mtd4
   2728 Name:                           ubi
   2729 Type:                           nand
   2730 Eraseblock size:                131072 bytes, 128.0 KiB
   2731 Amount of eraseblocks:          1000 (131072000 bytes, 125.0 MiB)
   2732 Minimum input/output unit size: 2048 bytes
   2733 Sub-page size:                  2048 bytes
   2734 OOB size:                       64 bytes
   2735 Character device major/minor:   90:8
   2736 Bad blocks are allowed:         true
   2737 Device is writable:             true
   2738 
   2739 <5>UBI: auto-attach mtd4
   2740 <5>ubi0: attaching mtd4
   2741 <5>ubi0: scanning is finished
   2742 <5>ubi0: attached mtd4 (name "ubi", size 125 MiB)
   2743 <5>ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes
   2744 <5>ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048
   2745 
   2746 we made a volume using "ubimkvol /dev/ubi0 -N liminix -S 825"
   2747 
   2748 and from ubinfo -a we can see
   2749 
   2750 0 ubootenv
   2751 1 ubootenv2
   2752 2 recovery
   2753 3 boot_backup
   2754 4 liminix
   2755 
   2756 Now we could use "ubiupdatevol /dev/ubi0_4 /path/to/ubifs.img"
   2757 to put a ubifs on that volume, but obviously we'd have to boot the
   2758 device into Liminix somehow first.
   2759 
   2760 Alternatively in the build environment we could use ubinize to
   2761 create the entire image that can be flashed to MTD, but
   2762 
   2763 - this will overwrite erase counters.
   2764 - we have to give it a config file that describes all the volumes,
   2765  and I'm guessing they need to match up with the existing ones
   2766  otherwise we trash the uboot env
   2767 
   2768 
   2769 Wed Oct 11 17:37:09 BST 2023
   2770 
   2771 We can write ubi volumes from u-boot.  Let's for the moment use
   2772 mkfs.ubifs and tftp those files to u-boot - we can figure out the
   2773 ubinize dance later
   2774 
   2775 We need either
   2776 
   2777 (a) to write an analogue of our jffs2 graft option for mkfs.ubifs, or
   2778 (b) to have a "cpio-like" mkfs.ubifs variant that reads filenames on stdin
   2779   and writes only those, or
   2780 (c) to create a "staging" directory during build with all the store folders that need to go into the filesystem
   2781 
   2782 although the least elegant, option (c) is the simplest and probably
   2783 not even slow, at least by comparison with unpacking the kernel source
   2784 tarball
   2785 
   2786 we used
   2787 uboot> tftpboot 0x40400000 result/rootfs
   2788 uboot> ubi write 40400000 liminix $filesize
   2789 
   2790 then can use ubifsmount ubi0:liminix ; ubifsls / to check that it wrote
   2791 something valid. To boot this:
   2792 
   2793 setenv serverip 10.0.0.1
   2794 setenv ipaddr 10.0.0.8
   2795 setenv bootargs 'liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:liminix  rootfstype=ubifs fw_devlink=off'
   2796 tftpboot 0x4007ff28 result/uimage
   2797 bootm 0x4007ff28
   2798 
   2799 The other thing we had to fix here is that activate wasn't being built
   2800 statically. Have to add -Xlinker -static to CFLAGS - I don't know if
   2801 this is a no-op on MIPS
   2802 
   2803 Mon Oct 16 20:51:08 BST 2023
   2804 
   2805 Here's a thing: the u-boot installed by openwrt on this device has a
   2806 ubifsload command, and it has a writable ubootenv. So instead of
   2807 having a separate partition for the kernel we could put the kernel in
   2808 the actual filesystem
   2809 
   2810 I think we should do this by excluding flashimage and including some
   2811 other module (to be written) instead. ubimage or somesuch, perhaps.
   2812 
   2813 So the image we wish to create is a ubifs with a kernel inside it in
   2814 /boot and we also need to change the u-boot env value of
   2815 
   2816 boot_production=led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
   2817 
   2818 so that it mounts the rootfs and finds /boot/uimage inside it
   2819 
   2820 From uboot this is setenv and saveenv; from a running linux this is fw_setenv
   2821 
   2822 Thu Oct 19 09:34:15 BST 2023
   2823 
   2824 setenv bootargs 'liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:liminix  rootfstype=ubifs fw_devlink=off'
   2825 
   2826 
   2827 ubifsmount ubi0:liminix
   2828 ubifsload 4007ff28 boot/uimage
   2829 bootm 0x4007ff28
   2830 
   2831 
   2832 Thu Oct 19 23:11:17 BST 2023
   2833 
   2834 Assuming you've done the openwrt installer to repartion the device,
   2835 what are the steps to install Liminix?
   2836 
   2837 1) build rootfs, which incorporates kernel
   2838 
   2839 2) from u-boot:
   2840 
   2841 uboot> ubimkvol /dev/ubi0 -N liminix -S 825
   2842 uboot> tftpboot 0x40400000 result/rootfs
   2843 uboot> ubi write 40400000 liminix $filesize
   2844 uboot> setenv boot_production 'led $bootled_pwr on ; ubifsmount ubi0:liminix; ubifsload 4007ff28 boot/uimage; bootm 4007ff28'
   2845 
   2846 What if we don't have a serial console? can we do all this from openwrt?
   2847 
   2848 Fri Oct 27 23:21:08 BST 2023
   2849 
   2850 setenv serverip 10.0.0.1
   2851 setenv ipaddr 10.0.0.8
   2852 setenv bootargs 'liminix earlyprintk earlycon=uart8250,mmio32,0xf1012000 ramoops.mem_address=0x8000000 ramoops.mem_size=0x40000 ramoops=max_reason=2 mem=128M earlycon=ttyS0 console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:liminix  rootfstype=ubifs fw_devlink=off'
   2853 setenv bootargs 'liminix  ramoops.mem_address=0x8000000 ramoops.mem_size=0x40000 ramoops=max_reason=2 mem=128M console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=ubi0:liminix  rootfstype=ubifs fw_devlink=off'
   2854 tftpboot ${kernel_addr_r} result
   2855 bootm ${kernel_addr_r}
   2856 
   2857 
   2858 ---
   2859 this is potentially worth checkng out because we do have very slow
   2860 decompress speed
   2861 
   2862 https://scm.linefinity.com/common/u-boot/commit/5818198e6a184963c6afc82178b23a64435ace6a
   2863 
   2864 Commit 5bb2c550b1 ("arm: mvebu: Move internal registers in
   2865 arch_very_early_init() function") implemented code movement according to
   2866 (now incomplete) comments which resulted in semi-broken code.
   2867 
   2868 The result is that I-cache is currently disabled for all Armada 38x boards
   2869 and maybe there are some other (unreported / undetected) issues.
   2870 
   2871 [...] After this change lzmadec command with lzma image of 0x7000000 bytes is
   2872 doing decompression just 5 seconds. Before this change it was 30 seconds.
   2873 
   2874 
   2875 Mon Oct 30 21:03:55 GMT 2023
   2876 
   2877 We have a kernel that boots on the Omnia, now we need to build a
   2878 rootfs. Given this device uses mmc for its primary storage, we should
   2879 use a block filesystem not a flash filesystem.
   2880 
   2881 
   2882 setenv serverip 10.0.0.1
   2883 setenv ipaddr 10.0.0.8
   2884 setenv bootargs 'liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/mtdblock0 rootfstype=ext4fs fw_devlink=off mtdparts=phram0:22M(rootfs) phram.phram=phram0,0x1300000,23068672,65536 root=/dev/mtdblock0'
   2885 tftpboot 0x1000000 tftpboot/uimage ; tftpboot 0x1300000 tftpboot/dtb ; tftpboot 0x29b0000 tftpboot/dtb; tftpboot 0x29c0000 initrd.img
   2886 
   2887 
   2888 Sat Nov  4 12:22:37 GMT 2023
   2889 
   2890 setenv serverip 10.0.0.1
   2891 setenv ipaddr 10.0.0.8
   2892 setenv bootargs 'liminix console=ttyS0,115200 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/mtdblock0 rootfstype=ext4 fw_devlink=off mtdparts=phram0:22M(rootfs) phram.phram=phram0,0x40300000,23068672,65536 root=/dev/mtdblock0'
   2893 tftpboot 0x40000800 tftpboot/uimage ; tftpboot 0x419b0800 tftpboot/dtb ; tftpboot 0x41a00000 initrd.img  ; tftpboot 0x40300000 tftpboot/rootfs
   2894 bootm 0x40000800  0x41a00000 0x419b0800
   2895 
   2896 kernel  0x40000800 + 2af400 = "402afc00"
   2897 rootfs  0x40300000 + 15f9400 = "418f9400"
   2898 dtb     0x419b0800 + 4e00 = "419b5600"
   2899 
   2900 Sun Nov  5 00:01:56 GMT 2023
   2901 
   2902 Open questions
   2903 
   2904 1) using -device loader for qemu phram, how do we choose appropriate
   2905 start address for all architectures? we could try to unify this
   2906 with the tftpboot approach, but that would mean providing the dtb
   2907 ourselves somehow which seems silly when qemu already does it
   2908 
   2909 2) flash erase block size for tftpboot phram, it need to match the hardware
   2910  - we don't use it at all for squashfs
   2911  - for jffs2 it needs to match if tftpboot is to use same rootfs image
   2912    as flash
   2913  - we don't have any way to do a tftpboot ubifs
   2914  - ext4 doesn't care
   2915 
   2916 3) the rootfstype needs thought.
   2917 
   2918 - for all but squashfs it implies an initramfs
   2919 - jffs2 can be flashed naively
   2920 - ubifs needs an installer to not clobber erase counts
   2921 - ext4 (for omnia) needs a block device and can't be flashed along
   2922   with the kernel/initramfs because it's a separate disk. or maybe
   2923   the omnia can load kernel from mmc?
   2924 
   2925 phram plus mtd_block is ok for ext4 for qemu, so that's one thing
   2926 fewer to deal with
   2927 
   2928 4) for tftpboot with a separate initramfs, is there any way to
   2929 make address selection easier?
   2930 
   2931 5) ubifs needs a different set of flash parameters (PEB, LEB etc)
   2932 
   2933 Tue Nov  7 23:19:10 GMT 2023
   2934 
   2935 We can flash the turris omnia from a USB stick
   2936 https://docs.turris.cz/hw/omnia/rescue-modes/
   2937 
   2938 it looks for omnia-medkit-latest.tar.gz and (I'm guessing) just
   2939 unpacks it onto the emmc.
   2940 
   2941 Perhaps we need per-device installation instructions in the docs.
   2942 
   2943 * rename defaultOutput to installerOutput
   2944 * attach some docs to the various options for installerOutput
   2945 * add a link from the device's rendered manual section to the
   2946  relevant installer output doc
   2947 
   2948 do we expect that outputs will build on each other? e.g.
   2949 turris omnia output is basically a tarball (other devices
   2950 might want this too) but with docs describing how to reset the
   2951 device and hold the button down until the led flashes four times
   2952 (other devices probably won't want this). maybe the model here
   2953 is that the turris output is a directory with a symlink to the
   2954 tarball and an informative README containing the instructions.
   2955 Although we also want the instructions in the manual where people
   2956 can read them before building anything.
   2957 
   2958 Fri Nov 10 21:27:50 GMT 2023
   2959 
   2960 Realising now that outputs and installers aren't the same thing.
   2961 
   2962 e.g. flashimage can be installed from u-boot or from kexecboot
   2963 
   2964 perhaps we distinguish between the
   2965 
   2966 "installation image":
   2967 - firmware.bin
   2968 - tarball
   2969 - ubifs image
   2970 - kernel + rootfs
   2971 
   2972 and "installer"
   2973 - kexecboot script
   2974 - u-boot script to flash squashfs image
   2975 
   2976 Sun Nov 12 17:17:30 GMT 2023
   2977 
   2978 What TODO?
   2979 
   2980 - "does the kernel live on the filesystem" depends on the bootloader
   2981   not the filesystem
   2982    - could we implement this with a module that adds to config.filesystem ?
   2983      it would depend on whether the bootloader can follow symlinks to
   2984      files not in /boot (probably fine unless crossing filesystems)
   2985    - the other question is how much futzing around in u-boot can/do we do
   2986      to tell u-boot how to boot? for grown-up u-boot it's not a
   2987      problem as we can saveenv but are there broken u-boots that would
   2988      prevent this?
   2989 
   2990 - kexecboot is unloved and documented in the wrong place. do we have a
   2991   test for it even?
   2992    - it won't work on aarch64 because it needs memmap=
   2993    - hardcodes memory size, which we should probably work out dynamically
   2994 
   2995 - how to put device name into the device docs
   2996   maybe devices
   2997 
   2998 - make config.boot.commandLine a single string
   2999 - finish omnia
   3000 - for installation on turris omnia we need tarball not ext4 image
   3001   (but keep the ext4 image anyway for tftpboot and possibly kexecboot)
   3002 [done] - now we have lim.parseInt should we use it consistently?
   3003 - usefulness tiers for devices ("stable", "experimental", "wip")
   3004 - params for ubi(fs) are a mess
   3005 - create an l2tp configuration
   3006 - iperf and tuning
   3007 - wlan country code
   3008 
   3009 
   3010 Fri Nov 17 17:30:39 GMT 2023
   3011 
   3012 kexec is fraught. I spent some time trying (unsuccesfully) to get a
   3013 kexecboot test running, but it doesn't work in qemu for the reason
   3014 that the kernel I built for qemu has SMP support but does not have
   3015 kexec_nonboot_cpu_func() - which is the needed function to stop
   3016 non-boot CPUs before jumping into the new kernel.  That this code is
   3017 all MIPS-specific (I have to assume that other architectures have
   3018 entirely different ways to stop non-boot CPUs?) is a bit worrisome: how
   3019 many other ways is kexec hardware-dependent?
   3020 
   3021 We have two scenarios where we may want to use it:
   3022 
   3023 1) the "installer": e.g. for UBI platforms, we want to plonk
   3024 a new ubifs on the device without clobbering the erase counters, which
   3025 means either doing it from U-Boot - needs serial connection -
   3026 or doing it from a Linux of some kind that is not running on the
   3027 filesystem we're toasting.
   3028 
   3029 2) reinstalling after the initial install - this is a big deal for
   3030 squashfs where there is no other way to change data, and an only slightly
   3031 smaller deal for jffs2, where there isn't much room to change much
   3032 data.
   3033 
   3034 Maybe instead of kexec we could do this by stopping services and then
   3035 pivot_root into a ramfs. We would, I assume, need to stop any processes
   3036 that have open files on the root fs, but we would need to have network
   3037 interfaces running. So we need a subset of services that run in recovery:
   3038 can make this a bundle
   3039 
   3040 * mount a ramfs
   3041 * copy the closure of the bundle into the ramfs
   3042 * stop all processes (including init?)
   3043 
   3044 sending pid 1 a signal FOO will cause it to run .s6-svscan/SIGFOO
   3045 
   3046 Fri Nov 17 23:53:43 GMT 2023
   3047 
   3048 So we need to extend .s6-svscan/finish to
   3049 
   3050 if test -e /maintenance/bin/init
   3051   cd /maintenance
   3052   mount --bind /maintenance/ /
   3053   chroot .
   3054   exec /bin/init -D maintenance
   3055 fi
   3056 
   3057 
   3058 foreground {
   3059   if { test -e /maintenance/bin/init }
   3060     cd /maintenance
   3061     foreground { mount --move /maintenance/ / }
   3062     foreground { chroot . }
   3063     redirfd -r 0 /dev/console
   3064     redirfd -w 1 /dev/console
   3065     fdmove -c 2 1
   3066     emptyenv /bin/init -D maintenance
   3067 }
   3068 ${s6-linux-init}/bin/s6-linux-init-hpr -fr
   3069 
   3070 
   3071 https://openwrt.org/docs/techref/sysupgrade
   3072 
   3073 s6-svscanctl -t /run/service
   3074 
   3075 Sun Nov 19 10:23:17 GMT 2023
   3076 
   3077 # cat `type -p reboot`
   3078 #!/nix/store/0v3q2lnh7bwg0ldk24lzmsdnmidmdvm6-execline-mips-unknown-linux-musl-2.9.3.0-bin/bin/execlineb -S0
   3079 /nix/store/j41b85ccx0rmf7lm5g13zqb7fs68l8y2-s6-linux-init-mips-unknown-linux-musl-1.1.1.0-bin/bin/s6-linux-init-hpr -r \$@
   3080 
   3081 
   3082 s6-linux-init-hpr calls hpr_send("", 0)
   3083 then
   3084 hpr_shutdown(what, &tain_zero, 0))
   3085 which sends "Shpr"[what] to  SCANDIRFULL "/" SHUTDOWND_SERVICEDIR "/" SHUTDOWND_FIFO
   3086 
   3087 which I assume is s6-linux-init-shutdownd.c
   3088 
   3089 it calls prepare_shutdown on socket read, which sets deadline, grace_time.
   3090 later (when?) it calls
   3091 
   3092   run_stage3(basedir) ; # we can see this by adding a message to rc.shutdown
   3093                         # this causes s6-rc services to be downed gently
   3094   s6-rc -v2 -bDa change
   3095 
   3096   prepare_stage4(basedir, what)
   3097 
   3098     creates a file STAGE4_FILE  with the contents:
   3099      s6-linux-init-umountall
   3100      scripts/rc.shutdown.final
   3101      s6-linux-init-hpr -f -r
   3102 
   3103   unsupervise_tree() ;
   3104 
   3105      goes through /run/service/*/supervise/control fifos
   3106      except shutdownd and logger, sending
   3107      "d" to each
   3108 
   3109      then does
   3110      s6_svc_write(SCANDIRFULL "/" S6_SVSCAN_CTLDIR "/control", "an", 2)
   3111      (this is a rescan not a terminate)
   3112 
   3113 #define SCANDIRFULL S6_LINUX_INIT_TMPFS "/" S6_LINUX_INIT_SCANDIR
   3114       (works out to be /run/service "/" ".s6-svscan")
   3115 
   3116 ls
   3117   kill(-1, SIGTERM) ;
   3118 
   3119 s6-rc -v2 -bDa change
   3120 cd /run/service
   3121 for i in s6-linux-init-runleveld s6rc-oneshot-runner s6rc-fdholder eth* getty ; do  s6-svc -d /run/service/$i; done
   3122 
   3123 
   3124 s6-rc -v2 -bDa change
   3125 cd /run/service
   3126 for i in  s6-linux-init-runleveld s6rc-oneshot-runner s6rc-fdholder eth*  ; do  s6-svc -d /run/service/$i; done
   3127 s6-svscanctl -an /run/service
   3128 
   3129 Wed Nov 22 22:01:02 GMT 2023
   3130 
   3131 - define a subset of services that run in maintenance mode.
   3132 - write a command that copies the closure of this bundle into
   3133   /run/maintenance
   3134 - create enough non-store filesystem (proc dev etc) to make it run
   3135 
   3136 Thu Nov 23 00:09:44 GMT 2023
   3137 
   3138 I was as surprised as anybody that this seems to work, at least
   3139 insofar as it has started a busybox sh process. there is a serious
   3140 deficit of symlinks to busybox, so almost no shell scripts work. and I
   3141 think we need an rc.init
   3142 
   3143 It would be worth tidying up the main s6 run-image quite a lot before
   3144 we go further with this
   3145 
   3146 We'd like to be able to reuse the s6 pseudofile structure (/etc/s6-rc
   3147 and /etc/s6-linux-init) but we can't make it a derivation because it's
   3148 pseudofiles (with funny permissions) not real files. Maybe we can
   3149 invoke the module as a function?
   3150 
   3151 Fri Nov 24 23:29:48 GMT 2023
   3152 
   3153 Turris TODO
   3154 
   3155 - see if network works (eth[012], which is which?)
   3156 - wireless drivers
   3157   [DONE] ath9k and ath10k, it's like old times
   3158   https://docs.turris.cz/hw/omnia/omnia/#turris-omnia-wi-fi-6
   3159   (note: other variant of the device has a MT7915AN, should we add
   3160    support for that as well?)
   3161 
   3162 - [DONE] feed the watchdog
   3163    it looks like compiling watchdog support is sufficient to stop the
   3164    thing from rebooting after three minutes, there is no need to actually
   3165    feed it from userspace.
   3166 
   3167 - "does the kernel live on the filesystem" depends on the bootloader
   3168   not the filesystem
   3169    - could we implement this with a module that adds to config.filesystem ?
   3170      it would depend on whether the bootloader can follow symlinks to
   3171      files not in /boot (probably fine unless crossing filesystems)
   3172    - the other question is how much futzing around in u-boot can/do we do
   3173      to tell u-boot how to boot? for grown-up u-boot it's not a
   3174      problem as we can saveenv but are there broken u-boots that would
   3175      prevent this?
   3176    - perhaps we need different boot "recipes" - e.g. some device
   3177      might want boot.scr and another something different
   3178 
   3179 - create installable tarball and test
   3180 - gpio thingy for SFP switching
   3181 - iperf
   3182 
   3183 - document the watchdog
   3184 - remove kexecboot? it's unloved and documented in the wrong place. do we have a
   3185   test for it even?
   3186    - it won't work on aarch64 because it needs memmap=
   3187    - hardcodes memory size, which we should probably work out dynamically
   3188 
   3189 - how to put device name into the device docs
   3190 
   3191 - [WONT] make config.boot.commandLine a single string
   3192   this sounds sensible but it just makes it harder to put useful comments
   3193   against command line fragments so that we know why they're there
   3194 
   3195 - usefulness tiers for devices ("stable", "experimental", "wip")
   3196 - params for ubi(fs) are a mess
   3197 - iperf and tuning
   3198 - wlan country code
   3199 - create an l2tp configuration
   3200 
   3201 Sun Nov 26 15:37:07 GMT 2023
   3202 
   3203 hatching a plan ... we could do "predictable" network interfaces like this:
   3204 
   3205  . add a devpath attr to network/link.nix
   3206  . get the kernel-issued name from "/sys${devpath}/net"
   3207  . use ip link set ${oldname} name ${newname}
   3208 
   3209 if we had the full iproute2 thng we could keep the old name as well:
   3210 # ip link property add dev wan altname eth1
   3211 
   3212 maybe we could do this with lua/netlink? no support in there currently
   3213 for RTM_NEWLINKPROP though
   3214 
   3215 Maybe we'll skip doing the altname. The attraction of it is that it
   3216 means the existing name isn't removed, so there's no possibility of a
   3217 race.
   3218 
   3219 The kernel will allocate eth0 when asked for eth%d and there is no
   3220 eth0. This might be the case where eth0 previously existed but it
   3221 just got renamed to lan
   3222 
   3223 Sun Nov 26 21:20:23 GMT 2023
   3224 
   3225 The wrinkle here is ifwait: using netlink we can't wait for an
   3226 interface by devpath but have to do it by name - which is a problem if
   3227 the interface is not yet present, because there won't be a devpath
   3228 in which to look up the name until it is.
   3229 
   3230 So we need a new flow
   3231 
   3232  - wait for devpath to exist
   3233  - get the ifindex (which shouldn't change, even if the name does)
   3234  - churn rtnetlink messages for that index
   3235 
   3236 We don't want to poll the sysfs file, but we can check it whenever
   3237 we get a netlink message
   3238 
   3239 Sun Nov 26 22:33:16 GMT 2023
   3240 
   3241 There is no way to refer to the hardware device for a bridge interface
   3242 by sysfs path because it has none. This is probably true of other
   3243 virtual devices as well.
   3244 
   3245 ls: cannot access '/sys/class/net/vbridge0/device': No such file or directory
   3246 
   3247 Also, there is no way to refer to the _netdevice_ of a hardware
   3248 interface without also knowing its default name, which doesn't help us
   3249 if enumeration changes
   3250 
   3251 ls /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0/net/
   3252 enp1s0
   3253 
   3254 So we should only be specifying devices by devpath if they're
   3255 hardware devices discovered by the kernel, not synthetic devices (that
   3256 we pick the name of anyway).
   3257 
   3258 So maybe we don't need to rewrite ifwait, we just do it after renaming
   3259 the device
   3260 
   3261 Wed Nov 29 21:28:37 GMT 2023
   3262 
   3263 How do we name outputs?
   3264 
   3265 fileystem image
   3266 with-boot filesystem image (e.g. ubifs for belkin)
   3267 tarball
   3268 with-boot tarball (e.g. omnia)
   3269 flashable combined image of kernel + filesystem (e.g. gl-mt*)
   3270 kernel + filesystem image + dtb + tftpboot glue
   3271 kernel + filesystem image + qemu script
   3272 
   3273 we could add initramfs as a separate thing for tftpboot and qemu
   3274 (and FIT images) but it would mean not sharing a kernel with
   3275 the outputs that require embedded initramfs
   3276 
   3277 we can enable with-boot variants of outputs by adding a
   3278 boot.loader config option. if we go that route, can we
   3279 use config options to drive the whole output thingy?
   3280 We could have a config option that just changes "defaultOutput"
   3281 but is that useful?
   3282 
   3283 Maybe the question is: we can choose a different output at build time
   3284 rather than editing configuration - how often is this useful? I think
   3285 tftpboot vs installable is about the only case.
   3286 
   3287 adding a /boot to a filesystem differs from making a combined
   3288 flashable image because it is a config change and not a composition
   3289 of two other already-built outputs.
   3290 
   3291 we could have done tftpboot that way as well, but we chose to unpack
   3292 and repack the fdt so we don't have to build two kernels - and also so
   3293 that we can have both outputs from the same configuration without
   3294 editing any files.
   3295 
   3296 for tftpboot we don't want to make the filesystem embed the kernel
   3297 if we need a separate kernel for booting (guessing we can't usually make
   3298 u-boot loopback mount a downloaded filesystem image). so that points to
   3299 not making it a config option,  _or_ to making the inclusion logic
   3300 (hardware wants a kernel in filesystem) && !(output == tftpboot)
   3301 which itself means the output somehow needs to be injected into the
   3302 config
   3303 
   3304 nix-build  -I liminix-config=./examples/hello-from-mt300.nix  --arg device "import ./devices/my-device" --arg output=tftpboot
   3305 
   3306 let's see if we can not do that?
   3307 
   3308 repacking a ubifs to add /boot is awkward and unpleasant
   3309 
   3310 Thu Nov 30 14:33:08 GMT 2023
   3311 
   3312 ~~We need a new boot-in-rootfs output which calls rootfs with
   3313 (config.filesystem  // { /boot ... }) when the device
   3314 boot type is extlinux~~
   3315 
   3316 ~~Do we need to put it in systemConfiguration as well? Yes,
   3317 otherwise liminix-rebuild won't install it~~
   3318 
   3319 We may have a problem here actually: if /boot is only set up after
   3320 reboot, by adding a link while running the initramfs, how did the
   3321 bootloader  find the kernel to boot in the first place? So
   3322 we need /boot to exist and to point to the new kernel before rebooting
   3323 into it, so we need to create it as a real directory along with /nix/store
   3324 when making the filesystem,
   3325 instead of relying on activate which will be too late.
   3326 
   3327 maybe we could extract the root directory structure creation
   3328 as a separate output from rootfs, then there is a single place
   3329 to put "and also add /boot"
   3330 
   3331 we will need to update pkgs/min-copy-closure/liminix-rebuild.sh
   3332 to add /boot
   3333 
   3334 we could make the contents of /boot a derivation and then
   3335 /boot itself is just a symlink to it. we would need to ensure that
   3336 the derivation is part of the system closure, though
   3337 
   3338 Sat Dec  2 15:33:07 GMT 2023
   3339 
   3340 - make rootfs the directory structure
   3341 
   3342 Sun Dec  3 23:31:35 GMT 2023
   3343 
   3344 Spent too much of the weekend first fighting run-liminix-vm.sh and
   3345 then rewriting it in Fennel, but we are now at the point that we can
   3346 boot u-boot in qemu. However, it maps the rootfs into high memory
   3347 where phram can find it, instead of putting it into a flash that
   3348 _qemu_ can see as flash, so u-boot is not able to boot the kernel or
   3349 at least not in a similar-to-hardware fashion. Once we've added that,
   3350 we need to write a test for boots-a-kernel-in-the-filesystem
   3351 
   3352 Mon Dec  4 19:46:58 GMT 2023
   3353 
   3354 We wanted a test that we are creating an image that u-boot can boot
   3355 using extlinux. Turns out that u-boot only has scripts to do this in
   3356 the case that the storage device has a partition table. Which is
   3357 representative of the Omnia mmc, but maybe not going to work for
   3358 jffs2/ubifs
   3359 
   3360 (For ubifs it might be OK, there's some concept of partitions
   3361 
   3362 ubifs_boot=if ubi part ${bootubipart} ${bootubioff} && ubifsmount ubi0:${bootubivol}; then devtype=ubi; devnum=ubi0; bootfstype=ubifs; distro_bootpart=${bootubivol}; run scan_dev_for_boot; ubifsumount; fi
   3363 
   3364 )
   3365 
   3366 So what do we need? a disk image with a partition table and an ext4fs
   3367 image in the only partition, and that partition to be bootable. Then
   3368 run-liminix-vm gets a --disk-image option which causes it to use
   3369 U-Boot instead of direct load (can we wrap it with something that sets
   3370 up the paths so it can find u-boot and qemu?)
   3371 
   3372 ok, we're going to define outputs.diskimage which is like
   3373 outputs.flashimage but it has a partition table. Then we can make a
   3374 qemu configuration with an ext4 filesystem and defaultOutput="diskimage"
   3375 and config.boot.loader.extlinux.enable = true
   3376 
   3377 sfdisk default behaviour for GPT partitioned disk is to start at sector 2048
   3378 (sectors are 512 bytes)
   3379 
   3380 Device     Start   End Sectors Size Type
   3381 disk.bin1   2048 14335   12288   6M Linux filesystem
   3382 
   3383 Tue Dec  5 23:54:22 GMT 2023
   3384 
   3385 Need mbr not gpt. At least, it takes up less space and it doesn't
   3386 inveigle us into EFI boot.
   3387 
   3388 This is close to working except that it doesn't want to boot a uimage
   3389 
   3390 Enter choice: 1
   3391 1:      Liminix
   3392 Retrieving file: /boot/initramfs
   3393 Retrieving file: /boot/kernel.gz
   3394 append: console=ttyAMA0 panic=10 oops=panic init=/bin/init loglevel=8 root=/dev/mtdblock0 rootfstype=ext4 fw_devlink=off
   3395 zimage: Bad magic!
   3396 
   3397 Thu Dec  7 19:33:02 GMT 2023
   3398 
   3399 virtio devices don't have standard major/minor so we can't create
   3400 device nodes for them at build time. Either we mount devtmpfs in the
   3401 initramfs (do we then have to move it to /target?) or we parse the
   3402 /sys/block/vda/vda1/dev node to get 253:1 or whatever
   3403 
   3404 Fri Dec  8 16:36:07 GMT 2023
   3405 
   3406 We'd like to remove the ugly special handling of qemu dtb. Here are
   3407 some thoughts
   3408 
   3409 1) qemu provides its guest the correct DTB for the configured hardware.
   3410 This is a desirable thing and we wish more platforms did it, so would
   3411 like not to replace it with a static dtb if we can avoid that
   3412 
   3413 2) so we need some kind of config option that says "platform provides the
   3414 device tree" (or alternatively, "we need a static dtb, platform doesn't
   3415 provide it").
   3416 
   3417 config.boot.platformProvidesDeviceTree
   3418 
   3419 
   3420 
   3421 Monday
   3422 
   3423 so where are we? we've removed the need for every hardware device to
   3424 be able to build flashimage, because not every hw device (looking at you,
   3425 bellkin/turris) works like that.
   3426 
   3427 for the belkin we can have imports = [ modules/outputs/ubimage ]
   3428 and extlinux enabled
   3429 
   3430 for the nwa from Raito we'd like to have imports = [ modules/outputs/ubimage ]
   3431 but the bootloader is mtd partition-based (or ubi volume? check?) -
   3432 so ubimage needs to know how to do that
   3433 
   3434 perhaps we need an output for "smash together a kernel and a
   3435 filesystem image that does not also contain a kernel, and don't
   3436 put a partition table on the front"
   3437 
   3438 diskimage {
   3439   partitionType = "mtd" ;  # or "mbr" or maybe "gpt"
   3440   partitions = [ o.uimage o.rootfs ];
   3441 }
   3442 
   3443 
   3444 
   3445 
   3446 for the turris we need to check but proceeding on the assumption
   3447 it wants a tarball with extlinux enabled
   3448 
   3449 https://docs.turris.cz/geek/schnapps/schnapps/#export-and-import
   3450 https://wiki.turris.cz/en/howto/omnia_booting_from_external_storage
   3451 
   3452 if we adopt this as our installation format then we are not
   3453 reformatting the flash and will keep the btrfs that the device
   3454 was shipped with.
   3455 
   3456 https://forum.turris.cz/t/update-to-5-1-x-by-medkit/13986/12
   3457 suggests that we could install a custom medkit from the
   3458 vendor OS
   3459 
   3460 => btrsubvol mmc 0:1
   3461 ID 257 parent 5 name /@
   3462 ID 259 parent 5 name /@factory
   3463 
   3464 there don't seem to be any other btr commands in u-boot
   3465 
   3466 Tue Dec 12 14:38:53 GMT 2023
   3467 
   3468 from the source code, to get to the various omnia revovery modes
   3469 
   3470 uboot> setenv omnia_reset 3 # or 1..n
   3471 uboot> setenv boot_targets rescue
   3472 uboot> boot
   3473 
   3474 // reset boot_targets to default value.
   3475 
   3476 Tue Dec 12 22:44:34 GMT 2023
   3477 
   3478 The hold-down-reset-until-n-leds-flash support depends quite heavily
   3479 on the post-boot Linux environment, in that it appears to be passing
   3480 omniarescue=3 rescue_mode=3 to the kernel command line -> pid 1
   3481 cmdline
   3482 
   3483 On the other hand, it is described as being able to boot from usb
   3484 stick if there's a boot.scr on the usb stick, so maybe we just do
   3485 that. The installation process could then be "boot usb, dd the
   3486 disk image to mmc, reboot, remove usb, realise we got the wrong root=".
   3487 Hmm.
   3488 
   3489 * Could we edit extlinux.conf for first boot? But bear in mind it's a
   3490 link to a store file.
   3491 
   3492 * Could we have extlinux.conf point at mmc0 and somehow override it for the
   3493 usb stick boot?
   3494 
   3495 * Could preinit try multiple root mounts until it gets one that works?
   3496 
   3497 * maybe we could detect omniarescue on kernel command line and switch to
   3498 usb root?
   3499 
   3500 * maybe outputs.usbstick could generate a customised rootfs image?
   3501 it might be unworkable to
   3502 
   3503 (narrator: it boots from mmc0 first and usb stick second, so that's not
   3504 particularly useful)
   3505 
   3506 
   3507 
   3508 
   3509 Device 0: Vendor: SanDisk Rev: 1.00 Prod: Cruzer Blade
   3510             Type: Removable Hard Disk
   3511             Capacity: 7632.0 MB = 7.4 GB (15630336 x 512)
   3512 ... is now current device
   3513 Scanning usb 0:1...
   3514 No EFI system partition
   3515 fdt_find_or_add_subnode: chosen: FDT_ERR_BADSTRUCTURE
   3516 ERROR: /chosen node create failed
   3517  - must RESET the board to recover.
   3518 
   3519 Thu Dec 14 15:32:39 GMT 2023
   3520 
   3521 from the omnia rescue image, we have
   3522 
   3523 ## Loading kernel from FIT Image at 01700000 ...
   3524 
   3525      Load Address: 0x00800000
   3526      Entry Point:  0x00800000
   3527 
   3528 
   3529 int lzmaBuffToBuffDecompress(unsigned char *outStream, SizeT *uncompressedSize,
   3530                              const unsigned char *inStream, SizeT length)
   3531 
   3532     err = image_decomp(os.comp, load, os.image_start, os.type,
   3533                            load_buf, image_buf, image_len,
   3534                            CONFIG_SYS_BOOTM_LEN, &load_end);
   3535 
   3536 configs/mvebu_db_armada8k_defconfig:CONFIG_SYS_BOOTM_LEN=0x800000
   3537    default 0x4000000 if PPC || ARM64
   3538    default 0x1000000 if X86 || ARCH_MX6 || ARCH_MX7
   3539    default 0x800000
   3540 
   3541 Fri Dec 15 19:21:53 GMT 2023
   3542 
   3543 Let's put some English words on the page to explain the above
   3544 gibberish. Since I upgraded the U-Boot on my Turris Omnia, it has
   3545 stopped being able to tftpboot.
   3546 
   3547 Uncompressing Kernel Image
   3548 lzma compressed: uncompress error 7
   3549 Must RESET board to recover
   3550 
   3551 "uncompress error 7" means there is not enough space in the output
   3552 buffer, and the output buffer is set by CONFIG_SYS_BOOTM_LEN which is
   3553 8192k, smaller than the uncompressed 12104200 of our kernel.
   3554 
   3555 So how can we fix?
   3556 
   3557 * one possibility is to do what the turris rescue mode does: build an
   3558 uncompressed uimage and then lzma the result.  u-boot can uncompress
   3559 the received file using lzmadec command. we'd want to do this without
   3560 breaking tftpboot on every other device that might not have an lzmadec
   3561 command
   3562 
   3563 * is there bloat in the kernel we could trim? probably not 4MB of it
   3564 
   3565 * we could build a custom u-boot with a bigger buffer. this _might_
   3566 not be a completely stupid idea as it's only the people prepared to
   3567 open the box that would be doing tftp workflows anyway, so provided
   3568 it's possible to replace u-boot without bricking it
   3569 
   3570 * we could try building zimage instead of uimage and use bootz to
   3571 start it
   3572 
   3573 Sat Dec 16 11:15:56 GMT 2023
   3574 
   3575 there is another use case for weird tftpboot derivation, which is the
   3576 device Raito has ported to where you need to wave a magic chicken at
   3577 u-boot on each command line
   3578 
   3579 Sat Dec 16 23:32:11 GMT 2023
   3580 
   3581 Turns out that even when using an uncompressed uimage, u-boot runs the
   3582 code to check the decompressed size, so that doesn't help at all.  But
   3583 booting a zImage works fine. I am committing a first pass of
   3584 modules/outputs/tftpbootlz.nix which does this using a lot of
   3585 copy-paste and (ironically) no lzma stuff at all.
   3586 
   3587 Sun Dec 17 16:25:30 GMT 2023
   3588 
   3589 it's started failing to mount root on arm32 because it's not recognising
   3590 the reserved-memory and something is trashing the phram filesystem
   3591 
   3592         reserved-memory {
   3593 
   3594                 phram-rootfs {
   3595                         reg = <0x1400000 0x1900000>;
   3596                         compatible = "phram";
   3597                 };
   3598         };
   3599 
   3600 Sun Dec 17 17:13:54 GMT 2023
   3601 
   3602 * We need to write the fdt phram differently on 64 bit vs 32 bit
   3603   (address-cells and size-cells should be 2 or 1)
   3604 
   3605 * this might be why it wasn't working on mips (can we test this
   3606 somehow in qemu or do we need to plug a device in?)
   3607 
   3608 qemu user-mode networking has a builtin tftp server.
   3609 
   3610 so we need a test that builds the tftpboot target for each qemu arch,
   3611 and then does run-liminix-vm with the --lan and --u-boot options, then
   3612 drives it with expect
   3613 
   3614 
   3615 * maybe tftpboot[lz] could be reintegrated with the regular one somehow
   3616 
   3617 Fri Dec 22 15:11:35 GMT 2023
   3618 
   3619 We have a working test for tftpboot, on all platforms, which took a
   3620 while.
   3621 
   3622 * tftpbootlz needs to be updated with what we learned, or merged
   3623 back into it
   3624 
   3625 * omnia install
   3626 
   3627 - build a stripped-down installer image which can be put on a
   3628  usb stick
   3629 - from openwrt on the device, use fw_setenv to set boot order
   3630 - boot into the installer image-
   3631  reformat the emmc as per requirements
   3632 - PREFIX=/mnt  liminix-rebuild
   3633 - profit
   3634 
   3635 Could we liminix-rebuild into /some/prefix/nix/store this would
   3636 actually be useful both for this boot-from-usb scenario and for
   3637 levitate. Looks like min-copy-closure doesn't need anything much on
   3638 the destination system except a working sshd and maybe an empty
   3639 /nix/store and /persist. Potentially we could even do it without
   3640 chroot (which would save running a second sshd), just add a prefix on
   3641 the paths
   3642 
   3643 what's the fallback? we're not touching the turris rescue
   3644 system (which is in nor flash) so we can expect all the
   3645 knightrider modes to continue to workto be able to
   3646 boot back into that and restore the vendor os? I think so
   3647 
   3648 Fri Dec 22 16:56:40 GMT 2023
   3649 
   3650 If we're going to use fw_setenv to change boot order,
   3651 we could equally well boot from tftp and not need the
   3652 usb stick
   3653 
   3654 fw_setenv boot_targets "tftp mmc0 nvme0 scsi0 usb0 pxe dhcp"
   3655 setenv bootcmd_tftp "echo TFTP BOOT"
   3656 
   3657 how can we get a tftp boot into few enough characters to reasonably
   3658 put it in an environment variable?
   3659 - use dhcp?
   3660 - embed bootargs into the fdt
   3661 
   3662 Fri Dec 22 21:10:53 GMT 2023
   3663 
   3664 * dtb needs size and offset of uncompressed root filesystem to add
   3665 reserved-memory and cmdline params
   3666 
   3667 * setting these in the dtb will change the size of the dtb
   3668 
   3669 * am assuming that we don't want the kernel to relocate into
   3670  ram that clashes with the root fs
   3671 
   3672 * should we care about phys mem fragmentation?
   3673 
   3674 conclusion:
   3675 
   3676 hardware.loadAddress
   3677 		  <uncompressed/relocated kernel>
   3678 tftp.loadAddress
   3679 		  <space for uncompressed root>
   3680 		  uimage or zimage
   3681 		  dtb
   3682 		  compressed root
   3683 
   3684 
   3685 [ should we rename hardware.loadAddress to something that expresses
   3686 more clearly it's the _kernel_ load address? ]
   3687 
   3688 [ another thing we need to do is stop building two kernels
   3689  because the uimage and zimage derivations are different ]
   3690 
   3691 Sat Dec 23 18:07:43 GMT 2023
   3692 
   3693 Addendum: for a zimage we need the compressed kernel to be at the
   3694 highest address, otherwise it prints "Starting" and then hangs
   3695 indefinitely.
   3696 
   3697 I believe this to be because the kernel decompressor sets up a stack
   3698 directly after the compressed payload, so will trash the fdt if it was
   3699 also there. The bug didn't exhibit on Turris Omnia with the same
   3700 layout, but maybe that was just luck.
   3701 
   3702 Sat Dec 23 18:11:04 GMT 2023
   3703 
   3704 Here is scope of work for Turris:
   3705 
   3706 (I) we need to build a suitable tftpboot image for
   3707 recovery/install.
   3708 
   3709 - disk partitioning tools and mkfs stuff
   3710 - kernel with all the filesystems
   3711 - dhcp client for connecting to wired network
   3712 
   3713 (II) we need instructions for building the real system
   3714 and using min-copy-closure to copy and install the system
   3715 configuration of the real one into /mnt
   3716 
   3717 (III) probably try the same recovery image as a USB stick
   3718 
   3719 (IV) I've lost track of what we're doing with /boot, does that work?
   3720 
   3721 (V) gpio thingy for SFP switching
   3722 
   3723 (VI) iperf, performance testing
   3724 
   3725 (VII) put device name and usefulness tiers ("stable", "experimental", "wip") in the docs
   3726 
   3727 (VIII) params for ubi(fs) are a mess
   3728 
   3729 (IX) wlan country code
   3730 
   3731 Tue Dec 26 16:23:37 GMT 2023
   3732 
   3733 I seem to have lost a chunk of notes here. Have added
   3734 systemConfiguration/bin/install which does the stuff to copy the right
   3735 files into /bin and wherever. There is currently no test for it though
   3736 
   3737 We could further simplify liminix-rebuild by adding --reboot as a flag
   3738 to install
   3739 
   3740 Tue Dec 26 21:38:43 GMT 2023
   3741 
   3742 To be any use, the test needs to be end-to-end - as in, rather than
   3743 just checking some files are copied, test that the machine rebooted
   3744 successfully
   3745 
   3746 Fri Dec 29 18:36:16 GMT 2023
   3747 
   3748 Our test for liminix-rebuild uses qemu block device and ext4 instead
   3749 of phram because -device loader doesn't seem to survive a reboot.
   3750 And it needs some free space in the ext4 partition inside the
   3751 mbr image so that it can install new stuff. However, the
   3752 filesystem is sized to be near-full.
   3753 
   3754 If the mbrimage output is to be much use, probably there should be
   3755 some way of telling it how big the disk is. Maybe it should use
   3756 hardware.flash.size?
   3757 
   3758 UBI also does a bad job of integrating into the hardware.flash hierarchy
   3759 (but ubi is also more complicated as the ubi volumes are "nested" inside
   3760 an MTD partition)
   3761 
   3762 To move forwards with this test I think I will make it not depend on
   3763 mbrimage for now, but we have to come back to this. Maybe importing
   3764 the mbrimage module provides new hardware.disk = { partitions, size etc}
   3765 config options.
   3766 
   3767 Sun Dec 31 23:52:04 GMT 2023
   3768 
   3769 https://developer.ridgerun.com/wiki/index.php/Setting_up_fw_printenv_to_modify_u-boot_environment_variables#Preparing_the_fw_env.config_file
   3770 
   3771 can we extract the fw_env config data somehow to produce an appropriate
   3772 file for the device?
   3773 
   3774 the device config needs to specify partition name and offset at minimum,
   3775 possibly also size.
   3776 
   3777 we can create a service that writes the config based on those values. but
   3778 if we are to be using fw_setenv from the shell, there is no service
   3779 which depends on that service. whatever defines the service also needs
   3780 to add it to system.services so that the recovery system can specify it
   3781 
   3782 Sat Jan  6 12:30:27 GMT 2024
   3783 
   3784 How do we min-copy-closure to the device when we don't have anything
   3785 hooked to the LAN port? It's rather easy to break the WAN  connection
   3786 when it involves going out to the internet and back
   3787 
   3788 * Don't want to plug it into the actual lan because it's doing dhcp service
   3789  and that is going to confuse
   3790 
   3791 * the machine we're copying from is loaclhost
   3792 
   3793 * we could do some kind of port forwarding thing? maybe a port forward on
   3794   run-border-vm qemu user networking ...
   3795 
   3796 * static route on loaclhost?
   3797 
   3798   512  sudo ip netns add test-lan
   3799   514  sudo ip link set dev enp1s0 netns test-lan
   3800 
   3801   525  sudo ip link add veth-test-lan type veth peer veth1 netns test-lan
   3802   533  sudo  ip netns exec test-lan ip link add name br0 type bridge
   3803   536  sudo  ip netns exec test-lan ip link set veth1 master br0
   3804   537  sudo  ip netns exec test-lan ip link set enp1s0 master br0
   3805        sudo  ip netns exec test-lan /nix/store/dh66q9k402pwpmmgc983xwmwb3vvvjbr-busybox-1.36.1/bin/busybox udhcpc -i br0
   3806 
   3807 then we could add a route to 10.8.0.1/32 with dev veth-test-lan ?
   3808 
   3809 Sat Jan  6 20:52:45 GMT 2024
   3810 
   3811 This is all beside the point right now because the _recovery_ system
   3812 does not run all this stuff - it just has a dhcp client on the lan
   3813 interface. We could plug it straight into the switch.
   3814 
   3815 
   3816 As we already just plugged it into enp1s0 on loaclhost, could we
   3817 do somethin to put it on the lan from there? add it to vbridge0?
   3818 
   3819 Sun Jan  7 15:30:57 GMT 2024
   3820 
   3821 Turns out we should have used a working ethernet cable.
   3822 
   3823 Sun Jan  7 15:31:14 GMT 2024
   3824 
   3825 OK, so
   3826 
   3827 # on device
   3828 mount /dev/mmcblk0p1 /mnt
   3829  [ take a snapshot if needed ]
   3830  [ clear out the turrisos files ]
   3831 ls /mnt/@
   3832 
   3833 # on build
   3834 
   3835 $ nix-build -I liminix-config=./examples/rotuer.nix --arg device "import ./devices/turris-omnia" -A outputs.systemConfiguration
   3836 $ nix-shell --run "min-copy-closure -r /mnt/@  root@recovery.lan   result "
   3837 
   3838 # on device
   3839 
   3840 $ mkdir /mnt/@/persist
   3841 $ /mnt/@/nix/store/swf3vn9bzx198c0cwp6naq0glqa9192n-make-stuff-armv7l-unknown-linux-musleabihf/bin/install /mnt/@/
   3842 
   3843 this fails because it tries to copy from the unprefixed nix
   3844 store. Also probably it should mkdir $prefix/persist. Also it needs to
   3845 create $prefix/boot: it's too late to do that with `activate`
   3846 because u-boot will need it to exist in order to load the initramfs
   3847 that runs activate
   3848 
   3849 Thu Jan 11 23:36:47 GMT 2024
   3850 
   3851 squashfs rootfsType doesn't rebuild when the kernel config is changed
   3852 
   3853 Mon Jan 22 19:04:45 GMT 2024
   3854 
   3855 setenv serverip 10.0.0.1
   3856 setenv ipaddr 10.0.0.8
   3857 compraddr=0x01000000
   3858 tftpboot ${compraddr} recovery.img.lzma
   3859 setexpr writeaddr ${filesize} + $compraddr
   3860 lzmadec ${compraddr} $writeaddr
   3861 usb start
   3862 usb dev 0
   3863 wdt dev watchdog@20300
   3864 wdt stop
   3865 usb write ${writeaddr} 0 ${filesize}
   3866 
   3867 
   3868 Thu Jan 25 11:55:36 GMT 2024
   3869 
   3870 openwrt:
   3871 CONFIG_BROADCOM_PHY=m
   3872 CONFIG_FIXED_PHY=y
   3873 CONFIG_GENERIC_PHY=y
   3874 CONFIG_IP17XX_PHY=m    ?
   3875 CONFIG_MARVELL_PHY=y
   3876 CONFIG_MVSW61XX_PHY=y  ?
   3877 CONFIG_RTL8366RB_PHY=m ?
   3878 CONFIG_RTL8366S_PHY=m ?
   3879 CONFIG_RTL8367B_PHY=m ?
   3880 CONFIG_SWPHY=y
   3881 CONFIG_USB_PHY=y
   3882 
   3883 CONFIG_FIXED_PHY=y
   3884 CONFIG_GENERIC_PHY=y
   3885 CONFIG_MARVELL_PHY=y
   3886 CONFIG_PHY_MVEBU_A3700_COMPHY=y
   3887 CONFIG_PHY_MVEBU_A38X_COMPHY=y
   3888 CONFIG_SWPHY=y
   3889 #
   3890 
   3891 Sat Jan 27 18:14:13 GMT 2024
   3892 
   3893 To make the recovery system (and tftpboot generally) more useful, it
   3894 would be good to resize the root fs on boot. Need to do this before
   3895 anything that writes to it
   3896 
   3897 Mon Jan 29 21:50:59 GMT 2024
   3898 
   3899 something is corrupted in the uncompressed rootfs
   3900 
   3901 
   3902 $ head -c $(printf "%d" 0x2be0000) rootfs | sha1sum
   3903 142571fe0436c18191727d1d4c2fd32163c1f2e1  -
   3904 => sha1sum 0x1000000 2be0000
   3905 sha1 for 01000000 ... 03bdffff ==> 142571fe0436c18191727d1d4c2fd32163c1f2e1
   3906 
   3907 but!
   3908 
   3909 $  head -c $(printf "%d" 0x2bf0000) rootfs | sha1sum
   3910 7aa004ba87c6772bade491fbade164e2dfe100f9  -
   3911 => sha1sum 0x1000000 2bf0000
   3912 sha1 for 01000000 ... 03beffff ==> 1a0923a94784d0c0b86006c5e6fff1649770dad3
   3913 
   3914 something is trashing something in the range 03be0000 - 03beffff
   3915 or else it's not being decompressed properly
   3916 
   3917 pxefile_addr_r=0x1900000
   3918 ramdisk_addr_r=0x2200000
   3919     scriptaddr=0x1800000
   3920 fdt_addr_r=0x2000000
   3921 fdtcontroladdr=7fb19b30
   3922 fdtfile=armada-385-turris-omnia.dtb
   3923      fdt_high=0x10000000
   3924   initrd_high=0x10000000
   3925 kernel_addr_r=0x1000000
   3926               0x1700000;
   3927               0x10000000
   3928 
   3929 Sun Feb  4 11:55:00 GMT 2024
   3930 
   3931 restructuredtext headings:
   3932 
   3933 https://devguide.python.org/documentation/markup/#sections
   3934 
   3935 
   3936 ####### chapter (one per filename)
   3937 *******
   3938 =======
   3939 -------
   3940 
   3941 Mon Feb  5 09:57:52 GMT 2024
   3942 
   3943 Before calling the Omnia "done" I'd like to get it to the point that
   3944 I can actually use it as a CPE. This means
   3945 
   3946 - writing something down about how we handle static addresses
   3947   - hosts that need static ipv6 can configure it themselves as ::n
   3948     where n is a small number. this won't clash with slaac
   3949   - the `hosts` param to dnsmasq can specify static ipv4
   3950 
   3951 - dealing with port forwards and allowed incoming in the firewall
   3952 
   3953 - would be quite cool to run sniproxy instead of forwarding to
   3954   loaclhost (extra credit)
   3955 
   3956 Sat Feb 10 18:23:54 GMT 2024
   3957 
   3958 ARGH KERNEL
   3959 
   3960 You can't define CONFIG_NETFILTER=y in a monolithic kernel and expect
   3961 later to separately build some modules that use it, because there are
   3962 a bunch of symbols that only get defined if certain other CONFIG
   3963 options are set at the time that the monolithic kernel is built.
   3964 
   3965 https://github.com/torvalds/linux/blob/master/net/netfilter/core.c#L689
   3966 
   3967 Another example is
   3968 https://github.com/torvalds/linux/blob/master/include/linux/netdevice.h#L160
   3969 - if you decide after building the kernel that you're going to build
   3970 some wireless modules, you can't do that without rebuilding the kernel
   3971 so that it knows to expect them
   3972 
   3973 The moral of the story seems to be: if you have a compiled Linux kernel source tree and you change some symbol from "is not set" to m and then run  make modules, you cannot in general expect that newly compiled  module to work.
   3974 
   3975 AP advertised VHT without HT, disabling HT/VHT/HE
   3976 
   3977 TODO
   3978 
   3979 - [done] support kernel version as parameter to builder pkgs/kernel/default.nix
   3980 - [done] extract the change in how module loading works from omnia device config,
   3981   and fix the other thing that uses it
   3982 - [axed] wlan module to take 'backported' as a parameter
   3983   half of the omnia conditionalConfig can go into the module
   3984 - [done] upgrade omnia to kernel v6
   3985 - figure out what mdns we need for local hostname resolution
   3986   (maybe bridging lan/wlan)?
   3987 - [DONE] slow wifi because "AP advertised VHT without HT, disabling HT/VHT/HE"
   3988 - [DONE] add local domain to secrets
   3989 - run sniproxy instead of forwarding
   3990 - [test] forward some port to loaclhost 22 for inbound ipv4 ssh
   3991 
   3992 
   3993 Mon Feb 12 21:50:35 GMT 2024
   3994 
   3995 # find  /run/service-state/dhcp6c.wan.link.pppoe/address/
   3996 /run/service-state/dhcp6c.wan.link.pppoe/address/
   3997 /run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM
   3998 /run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/valid
   3999 /run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/preferred
   4000 /run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/len
   4001 /run/service-state/dhcp6c.wan.link.pppoe/address/2001-8b0-1111-1111-0-ffff-51bb-4cf2_LFoo015bSsM/address
   4002 #
   4003 
   4004 valid 7199 preferred 3599
   4005 
   4006 Tue Feb 13 19:44:57 GMT 2024
   4007 
   4008 Before we put this back live, would be good to
   4009 
   4010 [done] 1) move the leases file into /persist
   4011 
   4012 I think we'll do /persist/service/<name>/ and change ssh to use the same
   4013 scheme.
   4014 
   4015 we could put mkpersist() in serviceFns which would check for /persist
   4016 and return a directory in /persist/service/ or /run/service-state
   4017 
   4018 (will something bad happen if we use /run/service-state? it will also
   4019 expose the thingy as an output, but whether it's accessible that way
   4020 will depend on whether there's a writable fs or not, which is unexpected)
   4021 
   4022 : rename service-state to  /run/services/outputs
   4023 : on boot
   4024 :  if /persist
   4025 :    create /persist/services/state and symlink /run/services/state to it
   4026 :  else create /run/services/state
   4027 
   4028 
   4029 [done] 2) maybe change the local domain back to .lan?  setting up
   4030   systemd-networkd with search domains is an awful faff
   4031 
   4032 [done] 3) work out what to do with incoming ssh from wan
   4033 
   4034 - For noetbook and thinkpad we have a vpn anyway so can expect to
   4035   reach loaclhost directly using ipv6
   4036 
   4037 - stop ssh from ever trying to get to our ipv4 address.
   4038   - we could get rid of A record for loaclhost.telent.net but
   4039     there are a bunch of CNAMES pointing at it for web servers.
   4040   - we could reject incoming connections to tcp4 port 22 in firewall
   4041     and then there is a clear signal to Dont Do That Then
   4042 
   4043 - for emergency use, dnat ipv4 2200 and 2201 to rotuer and loaclhost
   4044 
   4045 Tue Feb 13 22:31:03 GMT 2024
   4046 
   4047 * the reason we can't reboot is that there is a service to add each
   4048 lan device to the bridge which does ifwait $dev running, which doesn't
   4049 return until there's something plugged in. So s6-rc hangs indefinitely
   4050 until the lan switch is fully populated. This is definitely a "next
   4051 milestone" thing.
   4052 
   4053 * another example of "thing that depends on other thing but which it
   4054   is actually OK if neither of them happen" might be "mount a
   4055   filesystem if there is a usb mass storage device attached"
   4056 
   4057 * I don't know if failover also fits into the model we don't quite
   4058   have. LTE route depends on pppoe not being healthy
   4059 
   4060 we can have services (or bundles) that aren't part of the default target,
   4061 and plumb them into events of some kind (netlink?) to bring them up/down?
   4062 
   4063 we can use s6-rc instanced services:
   4064 https://skarnet.org/software/s6/instances.html
   4065 
   4066 "s6-instance-create and s6-instance-delete are relatively expensive operations, because they have to recursively copy or delete directories and use the synchronization mechanism with the instance supervisor, compared to s6-instance-control which only has to send commands to already existing supervisors. If you are going to turn instances on and off on a regular basis, it is more efficient to keep the instance existing and control it with s6-instance-control than it is to repeatedly create and delete it. "
   4067 
   4068 Probably we need something that reads netlink messages and converts
   4069 them to a format that we can use to control services. Is there a
   4070 benefit to using services here and not just running commands? it means
   4071 the system state change we desire will stay changed.
   4072 
   4073 TODO items not to lose track of
   4074 
   4075 - speed testing (iperf)
   4076 - make gl-ar750 tftpboot build again
   4077 - finish belkin
   4078 - install sniproxy
   4079 - is there something simple we can do to make it reboot again?
   4080 - turn rotuer,extneder examples into "profiles" that don't embed
   4081   hardware specifics
   4082 
   4083 Thu Feb 15 11:50:56 GMT 2024
   4084 
   4085 1) to make tftpboot work with old bootm implementations we need
   4086 
   4087 - compressed root
   4088 - uncompressed root
   4089 - kernel with dtb
   4090  dtb needs to know where uncompressed rootfs is and how big
   4091 
   4092 2) if the image is a zImage (arm32) or an Image (arm64) we have to stick
   4093 with the three-arg bootz, and the dtb has to be lower in ram than the kernel
   4094 
   4095 Fri Feb 16 15:43:32 GMT 2024
   4096 
   4097 DHCP6c refresh is still wrong. We get updates for an address that
   4098 hasn't changed prefix or length, when the expiry times have changed,
   4099 and we can't action that by remove;add because remove will wipe out
   4100 any routes through the interface but add won't put them back
   4101 
   4102 We can use "change" for both adds and changes, but we need to know that
   4103 a change is not a delete
   4104 
   4105 The "identity" of an address is the address itself: kernel won't
   4106 let you add the same address with two different prefixes.
   4107 
   4108 Keeping it simple, we could call "change" on every address in the
   4109 new-addresses list and "del" on every address in old-addresses
   4110 that is no longer in new-addresses
   4111 
   4112 If the upstream has changed length, "ip addr change" is ignored,
   4113 so it needs to be in deleted as well as added/changed
   4114 
   4115 Fri Feb 16 19:37:08 GMT 2024
   4116 
   4117 [    3.839775] cfg80211: module verification failed: signature and/or required key missing - tainting kernel
   4118 [    4.156952] ath10k_pci 0000:00:00.0: enabling device (0000 -> 0002)
   4119 [    4.165756] ath10k_pci 0000:00:00.0: pci irq legacy oper_irq_mode 1 irq_mode 0 reset_mode 0
   4120 [    4.399285] ath10k_pci 0000:00:00.0: qca9887 hw1.0 target 0x4100016d chip_id 0x004000ff sub 0000:0000
   4121 [    4.408906] ath10k_pci 0000:00:00.0: kconfig debug 1 debugfs 0 tracing 0 dfs 0 testmode 0
   4122 [    4.420096] ath10k_pci 0000:00:00.0: firmware ver 10.2.4-1.0-00047 api 5 features no-p2p,ignore-otp,ski
   4123 p-clock-init,mfp,allows-mesh-bcast crc32 62f7565f
   4124 [    4.467443] ath10k_pci 0000:00:00.0: board_file api 1 bmi_id N/A crc32 546cca0d
   4125 [    5.472096] ath10k_pci 0000:00:00.0: htt-ver 2.1 wmi-op 5 htt-op 2 cal file max-sta 128 raw 0 hwcrypto
   4126 [    5.585796] ath: EEPROM regdomain: 0x0
   4127 [    5.589712] ath: EEPROM indicates default country code should be used
   4128 [    5.596364] ath: doing EEPROM country->regdmn map search
   4129 [    5.601875] ath: country maps to regdmn code: 0x3a
   4130 [    5.606831] ath: Country alpha2 being used: US
   4131 [    5.611425] ath: Regpair used: 0x3a
   4132 [    6.742365] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
   4133 [    6.903389] random: hostapd: uninitialized urandom read (1027 bytes read)
   4134 [    8.169901] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
   4135 [   14.450193] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
   4136 [   15.518682] random: hostapd: uninitialized urandom read (1027 bytes read)
   4137 [   16.762697] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
   4138 [   23.030622] ath10k_pci 0000:00:00.0: pdev param 0 not supported by firmware
   4139 [
   4140 
   4141 
   4142 Tue Feb 27 23:16:27 GMT 2024
   4143 
   4144 We made it a full week with rotuer running internet chez nous and no
   4145 need for an intervention, so I am happy to call it "production". There are
   4146 still things that need fixing but they're mostly within scope for
   4147 a services refresh
   4148 
   4149 I have embarked on "profiles" by creating a wap.nix
   4150 
   4151 I think we could have a service module for resolvconf
   4152 
   4153 It would be good to build a wap.nix example for the belkin and we
   4154 could start looking at ubifs
   4155 
   4156 I've lost a chunk of notes about using events to drive desired service
   4157 state. There is probably only going to be one udev listener, so
   4158 what if we have udev as a config key thusly
   4159 
   4160 udev.rules = [
   4161 {
   4162   match = {
   4163    SUBSYSTEM = "rpmsg";
   4164     ATTR.name = "DATA5_CNTL";
   4165   };
   4166 
   4167   service = longrun {
   4168     name = "lte-modem";
   4169     run = "blah blah blah";
   4170   };
   4171 }
   4172 
   4173 # this one would be provided by the bridge module instead of
   4174 # adding bridge member services to the default target
   4175 
   4176 {
   4177   match = {
   4178     SUBSYSTEM="net";
   4179     ID_PATH="pci-0000:04:00.0";
   4180     ATTR.operstate = "up";
   4181   };
   4182 
   4183   service = oneshot {
   4184     up = "ip link set dev $dev master $(output ${primary} ifname)";
   4185     down = "ip link set dev $(output ${member} ifname) nomaster";
   4186   }
   4187 }
   4188 ]
   4189 
   4190 This works for udev/sysfs, but we want a similar architecture(sic) for
   4191 user-generated target state so we could have services that run on e.g.
   4192 "is the ppp0 service healthy" or not. Probably there isn't a top-level
   4193 config key for each service though
   4194 
   4195 services.wan = svc.ppoe.build   { .... };
   4196 services.lte = watcher.build {
   4197   watching = services.wan;
   4198   match =  {
   4199     # an expression matching the outputs of the service
   4200     # to be watched
   4201     health = "failing";
   4202   };
   4203   service = oneshot {
   4204     run = "start_lte_blah";
   4205   };
   4206 }
   4207 
   4208 thing is, we could use this syntax also for sysfs watches, but not vice versa
   4209 
   4210 ... but it's not quite the same because here we're doing static matches
   4211 on contents of files, whereas the udev one is a query expression on the
   4212 sysfs database. we might need that flexibiity to implement "mount the
   4213 backup drive no matter _which_ damn sda_n_ device it appears as". I don't
   4214 know if there's the same need for service outputs - postulate the
   4215 existence of a collection of services which are all similar enough that
   4216 some other service can watch them all and do $something when one of
   4217 the changes state. Or a single service with very complicated outputs.
   4218 For example, something could watch the snmp database and update service
   4219 status depending on what it finds. Or something something mqtt...
   4220 
   4221 we find that the "match" needs to be interpreted differently according
   4222 to the thing being watched. perhaps the service being watched needs to
   4223 provide a "watch me" interface somehow which accepts match criteria and
   4224 outputs a true/false. Something else then needs to
   4225 
   4226 
   4227 services.addmember = services.udev.watch {
   4228   match = {
   4229     SUBSYSTEM = "net";
   4230     ID_PATH = "pci-0000:04:00.0";
   4231     ATTR.operstate = "up";
   4232   };
   4233 
   4234   service = oneshot {
   4235     up = "ip link set dev $dev master $(output ${primary} ifname)";
   4236     down = "ip link set dev $(output ${member} ifname) nomaster";
   4237   };
   4238 }
   4239 
   4240 Sat Mar  2 15:37:29 GMT 2024
   4241 
   4242 Simply put, what I think it boils down to is that we want a service
   4243 which acts as an actuator or control switch for another service,
   4244 and will start/stop that controlled service according to some
   4245 criteria.
   4246 
   4247 services.addmember = svc.network.ifwatch.build {
   4248   interface = config.hardware.networkInterfaces.lan1;
   4249 
   4250   # this should be part of the definition not the params
   4251   service = oneshot {
   4252     name = "member-${bridge}-${interface}";
   4253     up = "ip link set dev $dev master $(output ${primary} ifname)";
   4254     down = "ip link set dev $(output ${member} ifname) nomaster";
   4255   };
   4256 }
   4257 
   4258 we could start by writing this. we need to adapt ifwait
   4259 
   4260 Sun Mar  3 17:09:21 GMT 2024
   4261 
   4262 this is annoyingly hard to test. the tests we'd like to write are
   4263 
   4264 1) when it gets events that don't match the requirement, nothing happens
   4265 2) when it gets an event that should start the service, the
   4266   service starts
   4267 3) when stop should stop
   4268 4) when start and already started, nothing happens
   4269 5) when stop and already stopped, nothing happens
   4270 
   4271 what do we do if service fails to start? s6-rc will eventually reset it
   4272 to "down", I think: do we need to take action?
   4273 
   4274 Mon Mar  4 20:46:55 GMT 2024
   4275 
   4276 # relevant but not correct for this model: https://www.forked.net/forums/viewtopic.php?f=13&t=3490
   4277 
   4278 # power on port 5
   4279 snmpset -v 1 -c private  192.168.5.14 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 integer 1
   4280 
   4281 # power off port 5
   4282 snmpset -v 1 -c private  192.168.5.14 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 integer 2
   4283 
   4284 # toggle off/on port 5
   4285 snmpset -v 1 -c private  192.168.5.14 .1.3.6.1.4.1.318.1.1.4.4.2.1.3.5 integer 3
   4286 
   4287 Wed Mar  6 18:24:29 GMT 2024
   4288 
   4289 What happens when we attempt to start the service but it fails?  We
   4290 assume the start was successful so we won't try and restart it again
   4291 next time we get an event that should cause it to start.
   4292 
   4293 Thu Mar  7 11:48:26 GMT 2024
   4294 
   4295 what next?
   4296 
   4297 - fennel script needs to know where s6-rc is
   4298 - some nix syntax
   4299 - update bridge module members.nix to use the new thing
   4300 
   4301 I can't find a ci derivation that uses the bridge.
   4302 
   4303 Mon Mar 11 20:31:45 GMT 2024
   4304 
   4305 Create a qemu config where wan and lan devices are bridged into a
   4306 single bridge
   4307 
   4308 start qemu paused
   4309 Use qemu monitor commands to no-carrier the network devices
   4310 set_link virtio-net-pci.1 off
   4311 set_link virtio-net-pci.0 off
   4312 
   4313 Boot the system
   4314 
   4315 See if both devices are bridge members
   4316 
   4317 See if reboot is possible
   4318 
   4319 Use qemu monitor commands to enable the network devices
   4320 set_link virtio-net-pci.1 on
   4321 set_link virtio-net-pci.0 on
   4322 
   4323 See if both devices are bridge members
   4324 
   4325 disable again,check if back to starting position
   4326 
   4327 
   4328 Wed Mar 13 00:00:16 GMT 2024
   4329 
   4330 aside: "trigger" is the least bad word I've thought of so far for
   4331 these services that stop/start other services
   4332 
   4333 telent: yeah, in general 'ps afuxww' (or s6-ps -H :)) is the way to solve this, look for hung s6-rc processes and in particular their s6-svlisten1 children, where the command line will show what service is still waiting for readiness
   4334 
   4335 Wed Mar 20 19:34:36 GMT 2024
   4336 
   4337 Because I forgot hoe to rebuild rotuer, I tihnk it is time to improve
   4338 support for out-of-tree configurations. So I've made
   4339 modules/profiles/gateway.nix and now I can copy rotuer.nix to
   4340 telent-nixos-config.
   4341 
   4342 Probably I should make nix-build work on the top-level derivation
   4343 and install liminix-rebuild as a binary?
   4344 
   4345 would be good if an out-of-tree config could specify the device
   4346 it was targeting?
   4347 
   4348 Fri Mar 22 20:49:54 GMT 2024
   4349 
   4350 Ideally liminix-rebuild could accept a configuration file that
   4351 specifies a liminix-config file, a target hostname (maybe plus ssh
   4352 port, credentials etc) and the device name. Not going to work on that
   4353 just now but it does mean we can punt on specifying the device inside the
   4354 liminix-config which is unreasonably circular.
   4355 
   4356 Maybe we'll just chuck a makefile in telent-nixos-config
   4357 
   4358 Fri Mar 22 22:14:32 GMT 2024
   4359 
   4360 For the service failover milestone we said
   4361 
   4362 a. A configuration demonstrating a service which is restarted when it crashes
   4363 b. A failover config where service B runs iff service A is unavailable
   4364 c. A config showing different pppd behaviour when interface is flakey (retry) vs ppp password is wrong (report error, wait for resolution)
   4365 
   4366 Sun Mar 24 23:41:27 GMT 2024
   4367 
   4368 TODO
   4369 
   4370 1) make liminix-rebuild bounce only affected services instead of
   4371   full reboot (what does it do about triggered services?)
   4372 2) sniproxy
   4373 
   4374 3) see if arhcive still works. usb disk hotplug would be a good candidate for
   4375 switching to triggers
   4376 
   4377 Mon Mar 25 19:35:47 GMT 2024
   4378 
   4379 to make the liminix-rebuild thing restart only affected services, it needs to
   4380 know when the new service is not like the old one. By default it does not
   4381 restart a service with a changed up/down/run script unless the name has
   4382 also changed, so we need to figure out how to generate a "conversion"
   4383 file with the services that are different
   4384 
   4385 pkgs/s6-rc-database/default.nix creates $out/compiled, we could add
   4386 $out/hashes to this
   4387 
   4388 the other thing making this fun is that we will need to run `activate`
   4389 (which is usually done in preinit) otherwise the new configuration's
   4390 fhs directories won't exist.
   4391 
   4392 so the plan woyuld be
   4393 
   4394 in liminix-rebuild, when reboot was not chosen,
   4395 
   4396 - run activate
   4397 - compare  /run/s6-rc/compiled/hashes (old services) with
   4398   /etc/s6-rc/compiled/hashes (new services)
   4399 
   4400 - whenever both files have the same column 1 and different
   4401 column 2, add that name to restart list
   4402 
   4403 (need to turn restarts.fnl into a lua script)
   4404 
   4405 s6-rc-update /etc/s6-rc/compiled/hashes restarts
   4406 
   4407 Tue Mar 26 23:18:53 GMT 2024
   4408 
   4409 activate overwrites /etc/s6-rc/compiled, which is a problem because
   4410 s6-rc-update expects to find the old compiled database here so that
   4411 it can know what to update
   4412 
   4413 Maybe config.filesystem should specify /etc/s6-rc/compiled.new
   4414 and something in early boot could symlink /etc/s6-rc/compiled to it
   4415 
   4416 Sat Mar 30 18:41:14 GMT 2024
   4417 
   4418 soft restart doesn't restart services that are invoked by trigger,
   4419 because it has to do -p -u default so that it prunes services that
   4420 were in the old config but not the new one. Ideally we need somehow
   4421 to notify the trigger that it should respawn its service. Maybe
   4422 we could add triggers to the force restart list, if there's a way
   4423 to detect which they are?  don't want to do it by adding files in
   4424 the service state directory if there may be oneshot triggers. Can
   4425 there be oneshot triggers?
   4426 
   4427 The hashes file is built when we build the service database, so we
   4428 could easily(?) add something in there to mark services that
   4429 need poking whenever there's a restart. It's not perfect because the
   4430 triggered services will be bounced unnecessarily, but remember that
   4431 the alternative is a reboot ...
   4432 
   4433 Mon Apr  1 00:18:50 BST 2024
   4434 
   4435 i) I don't know if digressing into remote log shipping is a tangent or
   4436 an important part of making services work well.
   4437 
   4438 ii) Should there be a single "machine state" value for all of the
   4439 trigger services to reference, or is it better that each trigger
   4440 service has its own private state, or (third option) one state
   4441 per "state source"? We previously handwaved that a state source
   4442 is a service
   4443 
   4444 services.addmember = services.udev.watch {
   4445   match = {
   4446     SUBSYSTEM = "net";
   4447     ID_PATH = "pci-0000:04:00.0";
   4448     ATTR.operstate = "up";
   4449   };
   4450 
   4451   service = oneshot {
   4452     up = "ip link set dev $dev master $(output ${primary} ifname)";
   4453     down = "ip link set dev $(output ${member} ifname) nomaster";
   4454   };
   4455 }
   4456 
   4457 
   4458 Tue Apr  2 19:55:25 BST 2024
   4459 
   4460 We could do a test script for udev usb disk mounting, which uses the
   4461 qemu monitor to add/remove a disk.
   4462 
   4463 
   4464 ./result/run.sh --flag -device --flag usb-ehci,id=xhci --flag -drive  --flag if=none,id=usbstick,format=raw,file=./stick.img
   4465 
   4466 (qemu) device_add  usb-storage,bus=xhci.0,drive=usbstick
   4467 
   4468 Fri Apr  5 17:11:46 BST 2024
   4469 
   4470 1) write a fennel thing that reads from the udev rebroadcast socket
   4471 2) and can check sysfs for state
   4472 3) set up mdevd in liminix
   4473 
   4474 
   4475 Sat Apr  6 13:23:02 BST 2024
   4476 
   4477 I wonder if we could replace preinit with an execline script? One for
   4478 the TODO stack
   4479 
   4480 
   4481 Sun Apr  7 14:03:29 BST 2024
   4482 
   4483 1) we want to know what messages are sent from mdevd under various circumstances
   4484  - actually, right now the only relevant circumstances are updown and inout
   4485 
   4486 2) we might get a wider variety of messages from real hardware?
   4487 
   4488 3) if we log the raw messages, pref. with timestamps, then we can
   4489 write tests for the parsing
   4490 
   4491 
   4492 therefore: write a program that opens the netlink socket and logs
   4493 all data received
   4494 
   4495 ----
   4496 
   4497 what's the minimum we need here?  we need the inout test to open a
   4498 uevent socket and use uevents to update some state that says whether the
   4499 backup drive is plugged in
   4500 
   4501 rather awkwardly, uevents don't have filesystem labels. so we also need
   4502 to run blkid to find the label of each partition, and ideally we do this
   4503 while the partition is present, not each time we get an event for it.
   4504 
   4505 We have DEVNAME, DEVTYPE, SUBSYSTEM to indicate that a filesystem of interest
   4506 may be present, we should use that as a trigger to scan any known
   4507 
   4508 
   4509 
   4510 add@/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
   4511 ACTION=add
   4512 DEVPATH=/devices/pci0000:00/0000:00:13.0/usb1/1-1/1-1:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1
   4513 SUBSYSTEM=block
   4514 MAJOR=8
   4515 MINOR=1
   4516 DEVNAME=sda1
   4517 DEVTYPE=partition
   4518 DISKSEQ=2
   4519 PARTN=1
   4520 SEQNUM=1528
   4521 
   4522 Some disks on loaclhost and noetbook have PARTNAME field - I assume
   4523 this is because they're GPT disks. Would it actually be better to use this
   4524 field than grovelling for filesystem label?
   4525 
   4526 Tue Apr  9 21:07:50 BST 2024
   4527 
   4528 Having waited for the appropriately labelled disk to appear, we then
   4529 also have to communicate its path to the service that mounts it
   4530 
   4531 - create a symlink
   4532 - or use an instanced service
   4533 
   4534 Creating a symlink will be fine if we can pass the symlink name as
   4535 a param to fswait
   4536 
   4537 Wed Apr 10 20:53:48 BST 2024
   4538 
   4539 We think that fswait will evolve into a more general
   4540 waiting-for-uevents tool. Maybe we could provide the matchers on the
   4541 command line:
   4542 
   4543 waituevent -l /dev/volumes/backup-disk -s mount-srv devtype=partition partname=backup-disk
   4544 
   4545 Thu Apr 11 23:09:43 BST 2024
   4546 
   4547 lcommit d3a2e3a4cb80b631df2ab79d463c2c4d1adef37b
   4548 commit 4a58cf9335116ce673fcf08f70f3bca921a4c9ad
   4549 commit afca6d4b63dd39062f02827b3c29e16904770216
   4550 
   4551 Sun Apr 14 19:50:27 BST 2024
   4552 
   4553 how to get this on to main:
   4554  - make uevent-watcher package (it's fswait renamed)
   4555  - make mount service use it
   4556  - module for mdevd
   4557  - add nellie (generalise for other netlink uses w/params pid/family/groups)
   4558 
   4559 Mon Apr 15 19:59:43 BST 2024
   4560 
   4561 plan:
   4562 
   4563 introduce uevent-watcher command, update test to use it
   4564 
   4565 make mount service use it
   4566 
   4567 
   4568 
   4569 
   4570 Tue Apr 16 18:59:25 BST 2024
   4571 
   4572 Another idea for maybe-not-now: tftp local/peer addresses could be
   4573 provided as top-level params (e.g. to nix-build).
   4574 
   4575 Wednesday
   4576 
   4577 Here's irony: this doesn't work with arhcive when the disk is already
   4578 plugged at boot time because mdevd-coldplug has already run by the
   4579 time uevent-watch has started. Perhaps it turns out after all that we
   4580 do need to be looking at state not events? (Not that we'd ever really
   4581 believed otherwise but it hadn't been apparent so far)
   4582 
   4583 
   4584 options
   4585 
   4586 - we could delay coldplugd to later in boot process. Don't know how:
   4587   it would have to depend on all trigger services.  (Actually this
   4588   is kind-of possible as they're all marked isTrigger)
   4589 
   4590 - we could make uevent-watch look in sysfs for matches before it opens
   4591   netlink socket. This would be an in-process recursive walk of sysfs
   4592   reading all the uevent files, which may or may not be an improvment
   4593   on having multiple mdevd-coldplug processes do a recursive walk
   4594   of sysfs writing all the uevent files so that they trigger events
   4595   for uevent-watch to pick up.
   4596 
   4597 - we could construct some kind of queryable sysfs database so that
   4598   all the watchers could use the same source of state, and we could
   4599   make mdevd-coldplug depend on its presence.
   4600 
   4601 Favouring option 3 as cleanest, and actually it doesn't need to read sysfs
   4602 if it gets all the coldplug events.
   4603 
   4604 
   4605 for each event
   4606  parse into path and attributes
   4607  paths[event.path] += event.attributes # only if add/change
   4608  do something with indexes to make queries cheaper
   4609 
   4610 a first guess for indices would be to index everything:
   4611 
   4612 index[attribute.name][attribute.value] +=  event
   4613 
   4614 and then throw away the indices that are useless: let's say, the
   4615 ones with more than 10% of events (we can tune this).
   4616 
   4617 To query, look at query field names and first get the corresponding
   4618 index that (1) exists; (2) has the smallest number of values, then
   4619 scan through that looking for paths that match on the other fields
   4620 
   4621 We don't need to be ludicrously fast because there is probably some
   4622 human event here that triggers this (disk added, network device
   4623 unplugged). We don't want to use all the RAM in the world, though.
   4624 Maybe 10% is too much.
   4625 
   4626 
   4627 We can probably TDD the hell out of this.
   4628 
   4629 How should we provide the query interface? Needs to be some kind of
   4630 IPC, like a socket.
   4631 
   4632 ----
   4633 
   4634 Could we do something quick in the meantime so I can make arhcive work
   4635 again? maybe add a second mdevd-coldplug oneshot that depends on our
   4636 mount service
   4637 
   4638 
   4639 Wed Apr 17 18:57:49 BST 2024
   4640 
   4641 I hatched a plan (and forgot to save this file) to build a service
   4642 that subscribes to uevents and retains state so that other services
   4643 can know about things that happened before they started. I'm wondering
   4644 if it's really needed though, because there could be one process to
   4645 read the socket and start/stop *all* the udev triggered services.  Not
   4646 sure how we'd describe this in nix though: how do all the other
   4647 services
   4648 
   4649 How we would do a uevent database service (sysfsq):
   4650 
   4651 for each event e from socket
   4652 
   4653 if e.action in (add, change)
   4654   path[e.path] = e.attribues
   4655 
   4656 if e.action == 'remove'
   4657   path.remove e.path
   4658 
   4659 (update-indices e)
   4660 
   4661 
   4662 (fn update-indices [event]
   4663   for each k in (keys event)
   4664     index.k.v += e)
   4665 
   4666 we also want to not maintain indexes when there are so many values in
   4667 the index entry to make searching it worthless.
   4668 
   4669 to retrieve, look at each criterion that has an index and choose the
   4670 index with fewest elements in the value. scan that index for the other
   4671 criteria
   4672 
   4673 there are 813 uevent files in sysfs on arhcive, is this all overkill?
   4674 maybe we could simplify using a hardcoded stopword list - e.g. don't
   4675 have indices for MAJOR, MINOR
   4676 
   4677 what are we going to use for querying? can't be netlink because that's
   4678 a shared medium (broadcast/multicast). unix dgram socket? alternative
   4679 would be to somehow use the filesystem as a database
   4680 
   4681 Wed Apr 17 22:00:29 BST 2024
   4682 
   4683 tests. assuming the sysfs setup from all-events.txt, we can write tests lik
   4684 
   4685 - there is a path for $foo
   4686 - the attributes are x, y, z
   4687 
   4688 - when I add a device with $attributes, I can recall it
   4689   - by path
   4690   - by attribute value
   4691 
   4692 - when I remove it again, I cannot access it by path or attributes
   4693 
   4694 - when I add a device with $attributes major minor foo bar baz
   4695   it is added to indices for foo bar baz but not major minor
   4696 
   4697 - when I remove it, it can no longer be found by looking in any index
   4698 
   4699 - when I query with multiple attributes, the search is performed
   4700   using the most specific attribute (= the attribute whose
   4701   value at this key has fewest elements)
   4702 
   4703 
   4704 
   4705 I am still looking for ways to avoid doing this, but it is potentially
   4706 the first of several "database" services that triggers could want to
   4707 use so maybe it's an emerging pattern.
   4708 
   4709 
   4710 https://github.com/philanc/minisock useful? we could almost replace
   4711 nellie with it only not quite (it hardcodes 0 as the "protocol" param
   4712 to socket())
   4713 
   4714 Fri Apr 19 20:55:22 BST 2024
   4715 
   4716 We could have a service that's present only when a devdb entry is
   4717 present. For example mount_disk only runs when partlabel=foo
   4718 
   4719 Or we could have a service that continues to run as the $somedatabase
   4720 service state changes and does different things depending on the
   4721 nature of those changes. For example, [I can't think of an example
   4722 now, but it was definitely an issue the other day, maybe I dreamt it]
   4723 I don't think this will be such an issue for devdb becuase there isn't
   4724 much in it that has continuously varying values. Maybe battery health
   4725 is the exception there
   4726 
   4727 The step ahead we're thinking here is: how do clients do a request?  A
   4728 single one-of request for state is fine but chances are that a client
   4729 will do that to get initial state and then need to open a netlink
   4730 socket to get updates: well, if we can feed them the initial state
   4731 filtered for their needs why can't we send them the relevant updates
   4732 as well? This makes the database server design a bit more complicated
   4733 as it needs to remember each client and their subscriptions, and then
   4734 send only relevant updates to each subscribed client
   4735 
   4736 * should a client be allowed multiple subscriptions on the same
   4737 connection?
   4738 
   4739 * do we guarantee that every message sent is matching the subscription
   4740 or can we send other stuff as well if it makes implementation easier?
   4741 it might defeat the purpose a bit because it means the client also
   4742 needs to filter, but the client will anyway have to do some message
   4743 parsing so they can distinguish add from remove
   4744 
   4745 * where do we start?
   4746 
   4747 Sun Apr 21 13:31:48 BST 2024
   4748 
   4749 We have the mechanics of it working (albeit implemented in the
   4750 simplest possible terms), we need to glue it to some I/O
   4751 
   4752 1) open a netlink socket and read the events from it
   4753 
   4754 2) "create a PF_UNIX socket of type SOCK_STREAM, and accept connections on it, then each time you accept a connection, you get a new fd"
   4755 
   4756 - accept connection
   4757 - read terms from it
   4758 - register callback that writes event to connected socket
   4759 
   4760 minisock has no support for "test if fd is ready" or "wait for [fds]
   4761 to become ready", either we need poll() or we could add a call for "is
   4762 this fd ready to read" and use coroutines. Fork minisock or add as
   4763 another library?
   4764 
   4765 [ if we fork minisock we could expose the protocol param to Lua
   4766 so we could use it for netlink ]
   4767 
   4768 Tue Apr 23 19:13:45 BST 2024
   4769 
   4770 we could convert from minisock to lualinux. if we can also use that to
   4771 get rid of nellie and/or lfs, the size tradeoff is minimal
   4772 
   4773 ---
   4774 
   4775 Is there some way we could test the devout event loop?
   4776 
   4777 I can register a fd with a callback
   4778 when the fd is ready, my callback is called
   4779 when the callback return true it remains registered
   4780 when the callback return true it is unregistered and the fd is closed
   4781 
   4782 loop.register
   4783 loop.registered?
   4784 loop.feed
   4785 
   4786 Tue Apr 23 20:34:03 BST 2024
   4787 
   4788 I think we could make the event loop abstraction leak less?
   4789 It's not actually a _loop_, all the actual GOTO 10 happens
   4790 outside of it
   4791 
   4792 [X] 1) see if we can do netlink in lualinux
   4793 [X] 2) if so, convert it to lualinux
   4794 [X] 3) add netlink socket to event loop
   4795 [X] 4) make it send messages to subscribers
   4796 [X] 5) package it
   4797 [X] 6) make uevent-watcher use it instead of netlink directly
   4798 [X] 7) write an inout test variant that has the stick inserted
   4799   at boot time already
   4800 
   4801 I'm also thinking we could wrap the raw fds from lualinux into small
   4802 objects with read and close methods? It would make testing easier if
   4803 nothing else - also use of with-open.  Maybe do that in anoia.
   4804 
   4805 when a subscriber connects we need to send them their matching current
   4806 state before subscribing them [ needs a test ]
   4807 
   4808 figure out what event format the subscribers want? lua-ish or send the
   4809 same messages as udev would? If we're going to send the originals,
   4810 should we store them alongside the parsed, or reconstruct from parsed?
   4811 
   4812 Sat Apr 27 21:52:11 BST 2024
   4813 
   4814 We have a passing inout test. Next thing to do is try it on
   4815 the actual arhcive hardware
   4816 
   4817 Next big thing is some kind of failovery service.  Almost-obvious
   4818 candidate is LTE failover with aaisp l2tp tunnel
   4819 
   4820 Tue Apr 30 23:27:30 BST 2024
   4821 
   4822 I want to connect my new ip camera to arthur without letting it reach the
   4823 internet, or the internet reach it.
   4824 
   4825 we could plug it into a gl.inet box running dhcp server on lan
   4826 and client on wan, then use NAT to expose the camera's http and rtsp
   4827 ports on whatever address it has on the wan interface
   4828 
   4829 Tue May  7 22:23:49 BST 2024
   4830 
   4831 If we want to build a config with an l2tp upstream, it needs an
   4832 underlying dhcp interface not pppoe as we can't use the bordervm l2tp
   4833 account simultaneously. Having bordervm do dhcp might be quite useful
   4834 anyway for other applications, although it will have to double-nat to
   4835 the internet. We could give it an aaisp /64 and have routable ipv6 but
   4836 maybe that's a level of faff too high.
   4837 
   4838 Given that we can build xl2tpd  and a service for it.
   4839 
   4840 
   4841 're using the same l2tp account for thingy that we use to simulate ppp,
   4842 we need an upstream which is not ppp
   4843 
   4844 We need a less shit coldplug that copes with filenames containing spaces (!)
   4845 
   4846 Fri May 10 00:33:14 BST 2024
   4847 
   4848 Getting xl2tp hackily running turned out to be not a lot of work. However,
   4849 we need to figure out routing
   4850 
   4851 - we need a route on lan device to the dns to lookup l2tp.aaisp.net.uk
   4852 - we need a route on lan device to l2tp.aaisp.net.uk
   4853 
   4854 also it doesn't die when the tunnel closes, which is a bit shit
   4855 
   4856 maybe this is where we lean into health check services
   4857 
   4858 a health check service is just a service that watches another service
   4859 and kills it if it's not healthy.
   4860 
   4861 for xl2tpd, "not healthy" is "there is no ppp process" or "there is no
   4862 tunnel" or "the tunnel has no sessions". I don't know how we
   4863 (robustly) test for no ppp process associated with the l2tp peer
   4864 
   4865 when ppp quits, does the tunnel come down?
   4866 in xl2tld.c child_handler we respond to sigchld by closing c->fd
   4867 and setting it to -1
   4868 
   4869 Sat May 11 17:55:04 BST 2024
   4870 
   4871 A better way to monitor the connection health would be to ping a
   4872 computer on the internet (preferably one that doesn't mind being
   4873 pinged).  If we combine autodial with "is $isp still there" then we
   4874 should have something fairly robust.
   4875 
   4876 xl2tpd spawns pppd, we should equip it with config that writes the
   4877 ppp outputs (ip address etc) to the xl2tp service directory so
   4878 that it can be used like a regular ppp. This will also make
   4879 it possible to have the health check work by pinging the peer address
   4880 
   4881 Sun May 12 22:33:09 BST 2024
   4882 
   4883 sleep until the interface is probably up
   4884 failure counter  = 0
   4885 loop indefinitely
   4886   get outputs/peer-address of watched ppp service
   4887   ping it
   4888   if ok
   4889     reset failure counter
   4890   else
   4891     increment failure counter
   4892   fi
   4893   if failure counter > threshold
   4894     bounce the ppp service
   4895     exit, if previous action didn't do that already
   4896   end
   4897   sleep(check interval)
   4898 end loop
   4899 
   4900 
   4901 # ps ax | grep l2tp
   4902    72 root      1316 S    s6-supervise l2tp.aaisp.net.uk.l2tp
   4903    73 root      1316 S    s6-supervise l2tp.aaisp.net.uk.l2tp-log
   4904   122 root      1428 S    {run.user} /bin/sh ./run.user l2tp.aaisp.net.uk.l2tp
   4905  1099 root      1428 S    {run.user} /bin/sh ./run.user l2tp.aaisp.net.uk.l2tp
   4906  1102 root      1104 S    {xl2tpd} /nix/store/i1bbqh7vybam03l6jzf4sm4np3k4ack5
   4907  1115 root      1420 S    grep l2tp
   4908 # s6-rc -d change l2tp.aaisp.net.uk.l2tp
   4909 # ps ax | grep l2tp
   4910    72 root      1316 S    s6-supervise l2tp.aaisp.net.uk.l2tp
   4911    73 root      1316 S    s6-supervise l2tp.aaisp.net.uk.l2tp-log
   4912   122 root      1428 S    {run.user} /bin/sh ./run.user l2tp.aaisp.net.uk.l2tp
   4913  1102 root      1104 S    {xl2tpd} /nix/store/i1bbqh7vybam03l6jzf4sm4np3k4ack5
   4914  1122 root      1420 S    grep l2tp
   4915 
   4916 
   4917 Mon May 13 19:45:59 BST 2024
   4918 
   4919 We need to do the usb id swithcing dance thing for the lte modem.
   4920 At startup it's 12d1:14fe, which is "mass storage mode", although the
   4921 disks seem to disappear as soon as they appear which is weird
   4922 
   4923 probably the mode switch should be triggered by device insertion
   4924 
   4925 usb_modeswitch -v 12d1 -p 14fe --huawei-new-mode
   4926 
   4927 https://github.com/pixelspark/tymodem?tab=readme-ov-file
   4928 
   4929 
   4930 Tue May 14 21:58:25 BST 2024
   4931 
   4932 [ we didn't need this. the first form is the default, the second
   4933 is what something on the internet said we should change it to, the
   4934 third is setting it back to default ]
   4935 
   4936 ^SETPORT:A1,A2;12,1,16,A1,A2
   4937 AT^SETPORT="FF;12,16"
   4938 AT^SETPORT="A1,A2;12,1,16,A1,A2"
   4939 
   4940 
   4941 
   4942 Wed May 15 21:55:11 BST 2024
   4943 
   4944 we can use uevent-watch to look for devtype=usb_device product=12d1/14fe/102
   4945 and trigger a oneshot that runs usb-modeswitch
   4946 
   4947 we can use uevent-watch to look for devtype=usb_device product=12d1/1506/102
   4948 and trigger a oneshot that runs the AT commands
   4949 
   4950 if wwan0 is a triggered service how can dhcp depend on it? arse
   4951 
   4952 - we can get reverse dependencies from s6-rc-db, so the sematics of
   4953 starting a triggered service could include starting everything it
   4954 enables
   4955 
   4956 - we don't want to inadvertently start it on boot by putting it in the
   4957 global config.services
   4958 
   4959 Thu May 16 09:09:44 BST 2024
   4960 
   4961 we could do something cleverish with the config.services at build time
   4962 by stripping from it everything depending on a trigger. but then how
   4963 _do_ they get started? the intent of putting it in config.services
   4964 is that it will be started when conditions are suitable.
   4965 
   4966 can we: go through each service in config.services, detect the trigger
   4967 that started it, and add it to a bundle named for that trigger?
   4968 
   4969 we need something in the triggering service to mark the triggered
   4970 service as not-for-boot, and then to apply that transitively to
   4971 everyting depending on it
   4972 
   4973 I don't think we have common code for triggers, so either we need to
   4974 add some or put this marking in all of the current examples
   4975 
   4976 Wed May 22 22:29:46 BST 2024
   4977 
   4978 # cat /sys/bus/usb/devices/1-1.2:1.2/uevent
   4979 DEVTYPE=usb_interface
   4980 DRIVER=huawei_cdc_ncm
   4981 PRODUCT=12d1/1506/102
   4982 TYPE=0/0/0
   4983 INTERFACE=255/2/22
   4984 MODALIAS=usb:v12D1p1506d0102dc00dsc00dp00icFFisc02ip16in02
   4985 
   4986 # cat /sys/bus/usb/devices/1-1.2:1.0/uevent
   4987 DEVTYPE=usb_interface
   4988 DRIVER=option
   4989 PRODUCT=12d1/1506/102
   4990 TYPE=0/0/0
   4991 INTERFACE=255/2/18
   4992 MODALIAS=usb:v12D1p1506d0102dc00dsc00dp00icFFisc02ip12in00
   4993 
   4994 neither of these is a tty. however, there's a ttyUSB0
   4995 diretory in there -
   4996 
   4997 # cat /sys/bus/usb/devices/1-1.2:1.0/ttyUSB0/uevent
   4998 DRIVER=option1
   4999 
   5000 # cat /sys/bus/usb/devices/1-1.2:1.0/ttyUSB0/tty/ttyUSB0/uevent
   5001 MAJOR=188
   5002 MINOR=0
   5003 DEVNAME=ttyUSB0
   5004 
   5005 
   5006 We can query devout using s6-ipcclient:
   5007 
   5008 $ s6-ipcclient -v /run/devout.sock  sh -c "echo devtype=wwan >&7; cat <&6 >&2"
   5009 
   5010 
   5011 we're going to need to expose sysfs parent attributes in devout,
   5012 so that we can tie together vendor/product and tty name
   5013 
   5014 - they don't come from netlink socket so we'll have to read the
   5015   filesystem
   5016 - we don't know if we can cache them indefinitely or if they change
   5017 - we also will want to match on parent attributes
   5018 - per https://www.kernel.org/doc/html/v4.16/admin-guide/sysfs-rules.html
   5019   we should do that by getting the parent directory, not by
   5020   following symlinks
   5021 
   5022 I think we are going to document "a rule depending on attrs won't
   5023 trigger if those attrs change silently without a uevent". attrs for a
   5024 path are rescanned only when a event for that path (or a child?)
   5025 is received.
   5026 
   5027 we need to avoid using stdio to read sysfs attributes because of the
   5028 need for atomicity
   5029 
   5030 Sun May 26 12:24:45 BST 2024
   5031 
   5032 cd /
   5033 mkdir -p /tmp/sys/devices
   5034 find /sys/devices -type f | while read F ; do
   5035    D=/tmp/$(dirname $F)
   5036    test -d $D || mkdir -p $D
   5037    test -r $F &&  cat $F > /tmp/$F
   5038 done
   5039 
   5040 Tue May 28 20:58:58 BST 2024
   5041 
   5042 To make testing easier, we pass the /sys mount point as a param
   5043 to (sysfs) via (database)
   5044 
   5045 This means that for event:match to work with attributes, the event
   5046 also has to point back to the database, or at least to sysfs. However
   5047 we'd like to do the attr tests after the regular uevent key tests
   5048 and the attrs tests after even that, because they're that mich slower.
   5049 
   5050 -----
   5051 
   5052 Let's change it up.  The database contains kobjects not events. A
   5053 kobject knows its mountpoint as well as its path, and implements the
   5054 attr and attrs methods
   5055 
   5056 
   5057 Sun Jun  2 20:58:47 BST 2024
   5058 
   5059 we have a new uevent-rule service that can start/stop its controlled
   5060 service based on uevent fields and sysfs attrs for the corresponding
   5061 device/any ancestor of its sysfs path
   5062 
   5063 we need
   5064 - a way of starting _dependent_ services of the controlled service:
   5065   we want to activate that whole sub-branch of the dependency tree
   5066 
   5067 - a way to not attempt to start dependents of the controlled service
   5068 at boot time: we don't want to put them in the default bundle if
   5069 they depend on stuff that's part of the default service set.
   5070 
   5071 what happens when a service depends on _two_ controlled services?
   5072 we want to start it only when _both_ of them are up. That discourages
   5073 any idea of creating a bundle for each controlled service and its
   5074 dependants
   5075 
   5076 Tue Jun  4 19:07:44 BST 2024
   5077 
   5078 we have to do it at runtime. I think we can add a file in the service
   5079 directory to identify that it's triggered (i.e. only run in response
   5080 to an event, we could use better terminology here(
   5081 
   5082 
   5083 for s in the reverse deps of $triggered
   5084   unless any? (s1:  {  s1.triggered && s1.down  }  )
   5085               s.dependencies
   5086     start s
   5087 
   5088 we can do this in ci, maybe adapt the inout test
   5089 
   5090 two triggered services, A with a uevent that does happen
   5091 and B which doesn't
   5092 
   5093 two dependent services; C depends on A only and D on A+B.
   5094 
   5095 each should write an output
   5096 we check that the output from C is present but not the one from D
   5097 
   5098 
   5099 
   5100 Tue Jun  4 22:22:20 BST 2024
   5101 
   5102 We can't have dependencies of triggered services unless we expose the
   5103 triggered service instead of the watcher from the module that sets up
   5104 uevent-watch. otherwise the user will be declaring their dependencies
   5105 on the watcher and they will start when the watcher does. We need to
   5106 invert it.
   5107 
   5108 Bother.
   5109 
   5110 services.mount-foo = oneshot {
   5111   name = "blah";
   5112   up = "mount /dev/disk/by-partlabel/mydisk";
   5113   runCondition = conditions.sysfs {
   5114     terms = { partlabel = "blah"; };
   5115     symlink = "/dev/disk/by-partlabel/mydisk";
   5116   }
   5117 }
   5118 
   5119 To process this, we need to
   5120 
   5121 - remove it from the default bundle
   5122 - create a service that _is_ in the default bundle which
   5123    starts this one when runCondition is true
   5124 
   5125 
   5126 How would it look for service conditions other than uevents
   5127 
   5128 Thu Jun  6 21:49:10 BST 2024
   5129 
   5130 runCondition can be a function that accepts the service to be
   5131 watched and returns a service that does the watching. The
   5132 derivation calls this function and makes the watched service
   5133 depend on the watcher.
   5134 
   5135 When adding services to the default bundle (wherever that happens, I
   5136 no longer remember) we need to check if the service has a controller
   5137 and add that instead of the service itself.
   5138 
   5139 s6-ipcclient -v /run/devout.sock  sh -c "echo subsystem=tty attrs.idVendor=12d1 >&7; cat <&6 >&2"
   5140 
   5141 Sun Jun  9 22:55:05 BST 2024
   5142 
   5143 services which depend on services that have controllers should not be
   5144 added to default bundle, otherwise they will try to start the controlled
   5145 service before its ready
   5146 
   5147 Tue Jun 11 20:00:04 BST 2024
   5148 
   5149 we can't look in /run/service/name  to see if it's controlled, because
   5150 if it's a oneshot that directory won't exist. likewise /run/s6-rc/servicedirs/
   5151 
   5152 we could add the controller to the dependencies, then
   5153 controlled? = (any dependency is a controller)
   5154 
   5155 what about generating a script at build time that has the knowledge
   5156 baked in?
   5157 
   5158 
   5159 to_start = reverse deps of service
   5160 print "to_start=$to_start"
   5161 for each service s1 in to_start
   5162   if isControlled s1
   5163      rd = reverse deps of s1
   5164      print "test_stopped s1 && not_to_start="$not_to_start $rd"
   5165 print ''
   5166 for s in $to_start; do
   5167   case " $not_to_start " in
   5168     *" $s "*) true;;
   5169     *) s6-rc -u change $s ;;
   5170   esac
   5171 done
   5172 ''
   5173 
   5174 ---
   5175 
   5176 would it help to make an empty bundle called "controlled" and have all
   5177 controlled services depend on it? no, because the condition for
   5178 skipping a service is that it depends on a _different_ controlled
   5179 service that's down
   5180 
   5181 s6-rc -u change $service
   5182 for s in $(s6-rc-db -d all-dependencies $service); do
   5183   if (s6-rc-db all-dependencies $s | grep controlled); do
   5184     # do nothing: if it's stopped, we don't want to start it,
   5185     # and if it's already running there's no need to.
   5186     # XXX what if it's running but its children are not?
   5187     # XXX 2 this fails as written because _every_ service $s depends
   5188     # on the controlled service $service
   5189   else
   5190     start s
   5191 
   5192 "[service] Names cannot be duplicated and cannot contain a slash or a
   5193 newline; they can contain spaces and tabs, but using anything else
   5194 than alphanumerical characters, underscores and dashes is discouraged"
   5195 
   5196  would this be simpler in fennel?
   5197 
   5198 (each [l (lines (io.popen (%. "s6-rc-db -d all-dependencies %s" service)))]
   5199   (if (not (controlled-ancestor l))
   5200     (tset to-start l true)))
   5201 
   5202 Sat Jun 15 08:51:21 BST 2024
   5203 
   5204 # do this at boot
   5205 for s in  $(s6-rc-db -d dependencies controlled); do
   5206   mkdir -p /run/services/controlled
   5207   touch  /run/services/controlled/$s
   5208 done
   5209 
   5210 
   5211 # now we can do this to start a service tree
   5212 
   5213 for controlled in $(cd /run/services/controlled/ && echo *); do
   5214   if down $controlled; then
   5215     blocks="$blocks $controlled "
   5216   fi
   5217 done
   5218 
   5219 for s in $(s6-rc-db -d all-dependencies $service); do
   5220   for dep in $(s6-rc-db all-dependencies $s)
   5221     case "$blocks" in
   5222       "* $dep *")
   5223       	: don't start
   5224         ;;
   5225       *)
   5226 	s6-rc -u change $s
   5227       ;;
   5228     esac
   5229   done
   5230 done
   5231 
   5232 Sun Jun 16 23:13:53 BST 2024
   5233 
   5234 what we are trying to do is set up an l2tp by hostname
   5235 
   5236 1) this means looking up the hostname in the dns
   5237 2) this means having a route to the dns server
   5238 3) this means parsing the space-separated list of dns servers
   5239   provided by dhcp
   5240 
   5241 we could write the servers each into their own file, but that
   5242 helps less than you'd think unless we give those files predictable
   5243 names
   5244 
   5245 Thu Jun 20 10:16:52 BST 2024
   5246 
   5247 now we have l2tp-over-wwan, we need to do the failover mechanism
   5248 
   5249 - can't have both l2tp and pppoe running at once (at least for aaisp)
   5250   because same creds used for both and starting l2tp will cause them
   5251   to route all traffic to the l2tp instead of the FTTx
   5252 
   5253 - we could have the wwan stick permanently configured and ready to go,
   5254   as long as we're not actvely using it unless the main connection is
   5255   b0rked
   5256 
   5257 - can we have the same odhcp stuff running and point it to either?
   5258   maybe renaming the wan interface would be an easy-ish way to do this
   5259 
   5260 we need some kind of health check on the main connection that will
   5261 bring up the backup if e.g. packet loss over x%. Or is lcp echo good
   5262 enough here? for multipath to the same backhaul, if some weird routing
   5263 cockup makes google unavailable from the main connection it will most
   5264 likely also be unavailable from the backup, so lcp echo is arguably better
   5265 
   5266 
   5267 on a side note, use of shell functions to get the output from another
   5268 service is a bit icky
   5269 
   5270 Fri Jun 21 21:05:21 BST 2024
   5271 
   5272 We can have a controller with two controlled services, which runs the
   5273 second one when the first one isn't working.
   5274 
   5275 how do we connect the dependent services (dhcp pd, defaultroute, anything
   5276 else dependent on wan) to the correct upstream?
   5277 
   5278 we can't use bundles because bundles just flatten to atomic services, there's
   5279 no either/or there
   5280 
   5281 controller
   5282   - main service
   5283   - backup service
   5284   - proxy service
   5285 
   5286 The proxy service is running when one of the main or backup services is
   5287 up.  It provides all the outputs of whichever backend service is active
   5288 
   5289 https://skarnet.org/software/s6/s6-svwait.html
   5290 
   5291 proxy could use "s6-svwait -U -o main backup" to wait for one of the two
   5292 backend services, provded that both are longruns
   5293 
   5294 so in the controller we start main-service, and if/when that fails start
   5295 backup-service. we run proxy-service if any of the backend services is
   5296 running, and use its outputs to indicate which.
   5297 
   5298 the proxy could just symlink to the backing service outputs directory,
   5299 or it could copy and translate if the main and backup services have
   5300 different outputs, so that it presents a common interface. I'm not
   5301 sure proxy is the best name but I haven't thought of a better.
   5302 
   5303 we can do a manual switch back to main-service by restarting the
   5304 controller.  we could do an automatic switch by adding logic to the
   5305 controller to make it restart itself.
   5306 
   5307 perhaps the controller has an output that indicates which backend is
   5308 active, then the proxy just needs to look at that to figure which one to
   5309 use.
   5310 
   5311 while true; do
   5312   if s6-rc -u change $primary; then # will wait until succeeded, or exit 1 if timeout
   5313     ln -sf $primary outputs/active
   5314     s6-rc -u change $proxy
   5315   elif s6-rc -u change $secondary;  then
   5316     ln -sf $secondary outputs/active
   5317     s6-rc -u change $proxy
   5318   else
   5319     rm outputs/active
   5320     s6-rc -d change $proxy
   5321   fi
   5322   # wait for the backend to die (down cleanup will
   5323   # remove outputs directory)
   5324   while test -d outputs/active/.outputs
   5325     inotifywait outputs/active/.outputs
   5326   fi
   5327   rm outputs/active
   5328   s6-rc -d change $proxy
   5329 end
   5330 
   5331 this script will when when primary dies, attempt to start primary: if
   5332 it doesn't come up, start secondary
   5333 
   5334 if the primary comes up and then goes down later, we'll start it
   5335 again - which isn't what we want. When the primary dies, we
   5336 want to try the secondary next
   5337 
   5338 backends="primary secondary tertiary etc"
   5339 rest=$backends
   5340 while true ; do
   5341   first="${rest%% *}"
   5342   rest="${backends#* }"
   5343   if test -n "$first"; then
   5344     if s6-rc -u change $first; then
   5345       ln -sf $first outputs/active
   5346       s6-rc -u change $proxy
   5347 
   5348       while test -d outputs/active/.outputs
   5349 	inotifywait outputs/active/.outputs
   5350       fi
   5351     fi
   5352     rm outputs/active
   5353     s6-rc -d change $proxy
   5354   else
   5355     rest=$backends
   5356   fi
   5357 done
   5358 
   5359 in this version when the secondary dies then we try the third backend
   5360 (round-robin). are there circumstances where we'd rather retry the primary?
   5361 Presumably there are circumstances where we would _not_ rather
   5362 retry the primary, otherwise why are we even providing a tertiary?
   5363 If we could answer that question then we'd know.
   5364 
   5365 
   5366 Mon Jun 24 21:22:34 BST 2024
   5367 
   5368 the controller needs to know the names of its backends, which is ugly
   5369 if they're computed names because we can't define the services themselves
   5370 first without their references to the controller
   5371 
   5372 mutual recursion ... maybe it's time to understand how this fixpoint
   5373 thing works
   5374 
   5375 Wed Jun 26 22:16:25 BST 2024
   5376 
   5377 s6 will restart the pppoe service when it dies, and keep doing this
   5378 indefinitely - unless the ./finish script returns 125. Note that this
   5379 is only true for longruns, but it's not as though oneshots can die
   5380 anyway as there's no process to fail.
   5381 
   5382 Sat Jun 29 21:43:10 BST 2024
   5383 
   5384 > s6-supervise says it restarts the supervised process when it exits
   5385   "unless told not to"; however s6-rc talks about "failed
   5386   transitions": if a s6-rc service doesn't signal readiness before
   5387   timeout-up expires, it is stopped and won't be restarted.  I *think*
   5388   the behaviour I am observing is that ./run may be invoked several
   5389   times if it dies without ever signalling readiness, and then it's
   5390   killed when the timeout is exceeded
   5391 
   5392 
   5393 ... so ... that's OK, probably. pppoe will stop running after n
   5394 lcp-echoes time out
   5395 
   5396 ----
   5397 
   5398 inotifywait apparently requires c++ and libgcc and transitively the
   5399 kitchen sink, which is a bit silly as we have linotify in lua. So
   5400 we should replace the failover scripty thing with a lua program
   5401 
   5402 (table.concat rdepends ", ")
   5403 
   5404 
   5405 Fri Jul  5 21:21:18 BST 2024
   5406 
   5407 
   5408 1970-01-01 00:01:00.797696621 wan-switcher      blocks (        modem-modeswitch, modem-atz, wan.link.pppoe, 194.4.172.12.l2tp, wan-proxy     )       rdepends (      194.4.172.12.l2tp       )       start ( 194.4.172.12.l2tp       )
   5409 
   5410 
   5411 why is it starting l2tp when it should depend on having a route to the
   5412 l2tp server
   5413 
   5414 Sat Jul  6 14:24:26 BST 2024
   5415 
   5416 The logic for up-tree is not correct, as it assumes that the
   5417 requested service is itself ready to start (so excludes it from
   5418 the blocked list). If the requested service is dependent on
   5419 some other block, it should not be started.
   5420 
   5421 [ I am confused. Isn't this what happens already? ]
   5422 
   5423 
   5424 @40000000000000441b51b24c wan-switcher  blocks (        modem-atz, modem-modeswitch, 194.4.172.12.l2tp, wan.link.pppoe, wan-proxy     )       rdepends (      194.4.172.12.l2tp       )       start ( 194.4.172.12.l2tp       )
   5425 
   5426 
   5427 # s6-rc-db all-dependencies  194.4.172.12.l2tp
   5428 route-05029a9e8e2c-ee8d76f34e9c
   5429 hostname
   5430 modem-atz
   5431 modem-modeswitch
   5432 wwan0.link
   5433 check-lns-address
   5434 resolve-l2tp-server
   5435 controlled
   5436 route-07d8f171cb5a-ee8d76f34e9c
   5437 wwan0.link.dhcpc
   5438 wwan0.link.dhcpc-log
   5439 194.4.172.12.l2tp-log
   5440 194.4.172.12.l2tp
   5441 s6rc-fdholder
   5442 s6rc-oneshot-runner
   5443 
   5444 Wed Jul 10 23:37:00 BST 2024
   5445 
   5446 I propose rewriting the admin section. Topics we need to cover
   5447 
   5448 * building liminix given a configuration
   5449 * installing for the first time
   5450   - refer to hardware section to find which of the following apply
   5451   - installation from openwrt
   5452   - installation from boot monitor
   5453 * upgrading
   5454   - when you have a writable filesystem
   5455   - using levitate
   5456 * using the running system (services, logs)
   5457 
   5458 we also need to expunge all mention of kexec
   5459 
   5460 and mention the upgrade choices in the Configuration section so
   5461 people don't build an unupgradable image and only find out later
   5462 
   5463 Fri Jul 12 21:20:00 BST 2024
   5464 
   5465 generalising the failover example:
   5466 
   5467 - usb stick may or may not need a modeswitch
   5468 - may need a different chat script
   5469 - usb ids
   5470 
   5471 Mon Jul 15 17:52:57 BST 2024
   5472 
   5473 DONE 1) Should round-robin be a callService service or a function a la
   5474 longrun/oneshot, or even an overridable package?
   5475 
   5476 DONE 2) maybe we should replace all liminix.callService with
   5477  config.system.callService
   5478 
   5479 3) for consistency, can we make the networking "primitives" into
   5480 services? answer: no.  the only thing left there is `ifup` which is a
   5481 function returning a string, not a derivation
   5482 
   5483 Tue Jul 16 18:25:41 BST 2024
   5484 
   5485 can we make the gateway profile able to use failover?  perhaps if we
   5486 add username and password as options to the pppoe service, then call
   5487 gateway with the pppoe service instead of building it _in_ the profile,
   5488 we can have gateways with other-than-pppoe for the wan
   5489 
   5490 (for a straight lte uplink, could pass the wwan interface as wan)
   5491 
   5492 Fri Aug  2 20:18:38 BST 2024
   5493 
   5494 Some thoughts about secrets
   5495 
   5496 1) clevis/tang is a mechanism to have encrypted local secrets that
   5497 can't be decrypted unless a particular network host is present. This
   5498 means we can reboot it unattended without having plaintext on the device,
   5499 but it doesn't address getting the secrets onto the device.
   5500 
   5501 when is this useful?
   5502 
   5503 - someone steals the router and doesn't steal the tang server, they can't have my secrets
   5504 
   5505 when not?
   5506 
   5507 - someone compromises the machine, gets root, and looks in /run
   5508 - doesn't address key rotation
   5509 
   5510 2) hashicorp vault or something like it can download secrets from
   5511 a networked server - then we just plonk them in /run. But I don't want
   5512 to pay for vault itself, so "something like" are the key words there
   5513 
   5514 3) Is sops relevant here? could we keep secrets in a big sops json/yaml
   5515 and serve the decrypted file over https?
   5516 
   5517 ==== so we have a plan, I think =====
   5518 
   5519 1) a secrets service that retrieves the secrets from some directory1
   5520 that isn't /nix/store and copies them to its outputs with minimal
   5521 permissions.  Services that need secrets can depend on the secrets
   5522 service and be restarted when secrets change
   5523 
   5524 1b) a service that monitors changes in secrets (e.g. using inotify
   5525 on /run/services/outputs/foo/bar) potentially doesn't need to restart
   5526 when the secrets change, so how do we know which ones to pass over?
   5527 This is a performance optimisation not a correctness issue
   5528 
   5529 2) as (1) but the secrets are encrypted and we use clevis to decrypt
   5530 
   5531 3) a secrets service that fetches the decrypted secrets as a JSON file
   5532 using HTTPS.  We can use this ourselves with SOPS and it will be easy
   5533 to adapt for Vault users.
   5534 
   5535 (What about fetching _encrypted_ secrets with https and then
   5536 decrypting locally? I don't think we can do this with clevis because
   5537 the machine that encypts has to be the machine that decrypts (ICBW).
   5538 
   5539 Sat Aug  3 22:28:24 BST 2024
   5540 
   5541 It would be useful maybe if the secrets could survive a reboot. Fetch
   5542 using HTTPS and then store locally using clevis. But actually all that
   5543 does is mean we've shifted from "can see the secrets server" to "can
   5544 see the tangd server" so maybe not especially useful
   5545 
   5546 * We can't put passwords in the secrets unless we have a service that
   5547 will change /etc/passwd if they change *
   5548 
   5549 we need a service that does the HTTPS call, parses the JSON response
   5550 and writes it as nested subdirectories
   5551 
   5552 can we encode permissions and ownership into the file? should we?
   5553 will some other secret store (say, Vault) know how to encode permissions
   5554 in the same way as we arbitrarily choose to?
   5555 
   5556 
   5557 Tue Aug  6 18:41:16 BST 2024
   5558 
   5559 I would like to know
   5560 
   5561 - why the docs aren't being built
   5562 - min-copy-closure error:  "cpio: unsupported cpio format, use newc or crc"
   5563 - can we avoid rebuilding this crapload of build packages?
   5564 
   5565 Wed Aug  7 18:36:09 BST 2024
   5566 
   5567 * a lua script that downloads a json file and turns it into outputs
   5568 * a service that runs the script and then pauses for 30 minutes
   5569 * the service will be restarted when it exits
   5570 
   5571 export SOPS_AGE_KEY=$(age -d key.age)  ; sops -a age1vearrjhv4x4cw6rfg2hdgqp46p4k673avezk3td5rd9ktrcrmslsljjsfq -e secrets.yaml > secrets.enc.yaml
   5572 
   5573 EDITOR="emacs -nw" SOPS_AGE_KEY=$(age -d key.age)  sops  secrets.enc.yaml
   5574 
   5575 Fri Aug  9 21:51:18 BST 2024
   5576 
   5577 we have a service that periodically fetches a json and writes the values
   5578 to its outputs
   5579 
   5580 we need to figure how to *use* that data
   5581 
   5582 - services that can't look in a file for their secrets might need a config
   5583 file to be rewritten
   5584 - service may need restarting to pick up a changed secret
   5585 - maybe service accepts secrets using environment variables (see also
   5586  previous point)
   5587 
   5588 we already have  a mechanism for watching service output changes, it's the
   5589 thing we use for picking up dhcp6 config
   5590 
   5591 it doesn't do the diff for you, you have to remember the old value and
   5592 see for yourself if the change is useful.
   5593 
   5594 what we'd like is something like this:
   5595 
   5596 svc.secret-watcher.build {
   5597   source = config.services.secret-service;
   5598   watch = ["wlan" "telent5"];
   5599   service = svc.hostapd {
   5600     params = {
   5601       # ....
   5602       wpa_passphrase = "$(output secret-watcher "wlan/telent5/wpa_passphrase")";
   5603     };
   5604   };
   5605 }
   5606 
   5607 but output is a shell function, so how do we get this substituted into
   5608 the config file? something at runtime needs to rewrite the config file
   5609 into /run and interpolate the values.
   5610 
   5611 the hostap service "run" script, before starting hostapd, needs to
   5612 copy the config file from the store into /run/somewhere and
   5613 interpolate secrets.
   5614 
   5615 we could have a reasonably general command to do interpolation
   5616 
   5617 echo 'wpa_passphrase={[ wpa_passphrase ]}' |  \
   5618   patch-secrets /run/services/outputs/secrets-service/wlan/telent5 {[ ]} \
   5619   > /run/services/state/${name}/hostapd.conf
   5620 
   5621 
   5622 The values might need quoting/escaping, and the quoting rules will
   5623 depend on the format of the file that needs to be generated. What if
   5624 we do an Erb-style thing and evaluate the bit inside quotes as
   5625 Lua - then we can provide any kind of escapes needed as lua functions
   5626 
   5627 wpa_passphrase={[ string.format("%q", wpa_passphrase) ]}
   5628 
   5629 We could for convenience provide squote(), dquote() etc functions
   5630 but the necessary rules for escaping might vary. How about
   5631 having shell() or json() or ? (what else? html?)  functions that
   5632 format and escape per the encoding rules for that language?
   5633 
   5634 
   5635 string.gsub(template_string, "%{%[.-%]%}", function(x)
   5636   load(x, x, "t", myenv)
   5637 end
   5638 
   5639 Sat Aug 10 23:43:15 BST 2024
   5640 
   5641 Every service that can be configured with secrets (at least, that uses
   5642 a configuration file) will need to be altered to interpolate at
   5643 startup
   5644 
   5645 Any service that passes params on the command line may be able to
   5646 use the "$(output " syntax still, but it does feel brittle (it always did)
   5647 
   5648 will we see any kind of pattern emerge so that we can provide
   5649 secrets-interpolation for config files in one place instead of
   5650 everywhere?
   5651 
   5652 svc.secret-watcher.build {
   5653   source = config.services.secret-service;
   5654   watch = ["wlan" "telent5"];
   5655   service = svc.hostapd.build {
   5656     params = {
   5657       # ....
   5658       wpa_passphrase = "{{ $(output secret-watcher "wlan/telent5/wpa_passphrase")";
   5659     };
   5660   };
   5661 }
   5662 
   5663 how does the watcher communicate to the inner service that it needs secrets
   5664 from x place?
   5665 
   5666 svc.secret-watcher.build {
   5667   source = config.services.secret-service;
   5668   watch = "wlan/telent5";
   5669   service = svc.hostapd.build {
   5670     secrets = config.services.secret-service;
   5671     params = {
   5672       # ....
   5673       wpa_passphrase = "{{ $(output secret-watcher "wlan/telent5/wpa_passphrase")";
   5674     };
   5675   };
   5676 }
   5677 
   5678 or something like
   5679 
   5680 let
   5681  secret = name: get-output config.services.secret-service name;
   5682 in svc.secret-watcher.build {
   5683   watch = "wlan/telent5";
   5684   service = svc.hostapd.build {
   5685     params = {
   5686       # ....
   5687       wpa_passphrase = secret "wlan/telent5/wpa_passphrase";
   5688     };
   5689   };
   5690 }
   5691 
   5692 which is transformed into some kind of attrset that the service can
   5693 interrogate and figure out how to interpolate? this would be an improvement
   5694 as the knowledge of what kind of quoting to use is within the service
   5695 
   5696 A reasonable question would be what happens if we reference outputs
   5697 from more than one service. Honestly I'd be happy to not support it
   5698 but it's made quite easy by this form of syntax
   5699 
   5700 Mon Aug 12 19:42:48 BST 2024
   5701 
   5702 what about if when we build the output template we'd have something
   5703 like this:
   5704 
   5705 wpa_passphrase={{
   5706   json_quote(output("/nix/store/eeeee-servicename/.outputs", "foo/bar"))
   5707 }}
   5708 
   5709 which it will get partly from its own knowledge and partly from
   5710 the thing that called it
   5711 
   5712 
   5713 let
   5714   literal_or_output = o:
   5715     if builtins.typeOf(o) == "string"
   5716     then builtins.toJSON o
   5717     else "output(${builtins.toJSON o.service}, ${builtins.toJSON o.path})"
   5718 in
   5719 ''
   5720 wpa_passphrase={{
   5721   json_quote(${literal_or_output(wpa_passphrase)$})
   5722 }}
   5723 ''
   5724 
   5725 builtins.toJSON is not the "correct" quoting regime for Lua strings,
   5726 but it's sufficient for printable ascii, and using unprintable
   5727 characters in Nix strings is asking for trouble in the first place
   5728 
   5729 Tue Aug 13 18:37:59 BST 2024
   5730 
   5731 next thing is secret-watcher service
   5732 
   5733 svc.secret-watcher.build {
   5734   watch = { service = config.services.secrets; path= "wlan/telent5"; };
   5735   service = svc.hostapd.build {
   5736     params = {
   5737       # ....
   5738       wpa_passphrase = {service= config.services.secrets; path= "wlan/telent5/wpa_passphrase"};
   5739     };
   5740   };
   5741   action = "restart"; # or "sighup" or "stop-start" or ?
   5742 }
   5743 
   5744 we can implement this using the same output watching thing as acquire-*.fnl
   5745 use
   5746 
   5747 - a fennel script that opens the service and calls events
   5748 - when an event path matches, do the action
   5749 
   5750 [ should the watched service do this restart thing itself? ]
   5751 
   5752 watch-outputs -r controlled-service watched-service path1 path2 ...
   5753 [-r or -R or -s n to send that signal number ]
   5754 
   5755 
   5756 TODO stack
   5757 
   5758 1) should we move all of the veneer-on-s6 scripts into a single package? s6-rc-up-tree, s6-rc-round-robin, watch-outputs, output-template
   5759 
   5760 2) convert all writeFennelScript calls to writeFennel
   5761 
   5762 3) implement if-modified-since in http-fstree
   5763 
   5764 Wed Aug 14 23:00:12 BST 2024
   5765 
   5766 we have a watch-outputs program, just need to hook it up to services
   5767 that need restarting
   5768 
   5769 if we follow the pattern that health-check uses, define a service
   5770 that runs a script to do
   5771 
   5772  s6-svwait -U /run/service/${name}
   5773  watch-outputs -r ${name} .....
   5774 
   5775 and then insert it into the dependencies of the service that needs
   5776 restarting
   5777 
   5778 Sat Aug 17 22:25:44 BST 2024
   5779 
   5780 hostapd is wrapping itself in a watch-outputs, so it restarts
   5781 when the secrets change. TODO
   5782 
   5783 [not worth it] 1) be smarter about the watched paths? e.g. find common prefixes?
   5784 
   5785 [done] 2) don't need to wrap at all if there were no secrets
   5786 
   5787 [done] 3) implement different kinds of restart
   5788 
   5789 4) extend to other services
   5790 [why?]- dnsmasq
   5791 [done] - pppoe / l2tp
   5792 [done] - ssh keys
   5793 
   5794 5) other sources
   5795 - local filesystem
   5796 - local filesystem with tang unlocking
   5797 
   5798 6) should we send authorization header?
   5799 
   5800 7) install on router
   5801 
   5802 8) docs/video
   5803 
   5804 
   5805 Tue Aug 20 22:45:04 BST 2024
   5806 
   5807 pppd is different because we do the stuff on the command line instead
   5808 of using a config file.  Though I suppose we could convert to a config
   5809 file if it makes it simpler to reuse the template code, and that would
   5810 mean that secrets were in the filesystem instead of exposed on the
   5811 command line
   5812 
   5813 Wed Aug 21 23:28:41 BST 2024
   5814 
   5815 We may need to patch dropbear to make it look for authorized keys in
   5816 somewhere under /run that we can control. Or we could have a separate
   5817 dropbearpubkeyagent service that overwrites those files when things
   5818 change (but only if home is writable, which it isn't). Or we could install
   5819 those files as symlinks to writable storage
   5820 
   5821 https://github.com/fabriziobertocci/dropbear-epka useful?
   5822 
   5823 Fri Aug 23 11:51:34 BST 2024
   5824 
   5825 Wrote a patch to dropbear that permits us to -U /run/dropbear/authorized_keys/%n
   5826 
   5827 We need to write dropbearpubkeyagent service, which listens alongside
   5828 the ssh service to create those files when secrets change. it doesn't need
   5829 to interact with the actual sshd, but we _do_ need to invoke the
   5830 sshd with -U if keys-from-secrets were requested
   5831 
   5832 we need somewhere to specify the secrets path to the keys
   5833 
   5834 sshd = svc.ssh.build {
   5835   port = 2222;
   5836   authorizedKeys = {
   5837     service = config.services.secrets;
   5838     path = "ssh/authorized_keys";
   5839   };
   5840 }
   5841 
   5842 will
   5843 
   5844  - start the pubkey watcher service
   5845  - add it as a dependency of sshd service
   5846 
   5847 vaguely uneasy about the difference between how we reference a
   5848 directory full of secrets here and how we reference a single static
   5849 secret in e.g pppoe. But maybe it's ok. the output reference just says
   5850 where the value is, it's up to the implementing service script to say
   5851 how it gets converted to useful form
   5852 
   5853 How do we reconcile this with config.users, which also has ssh auth
   5854 keys? Maybe we just say it overrides.
   5855 
   5856 What if someone provided static data for authorizedKeys?
   5857 (1) we would want it to be a attrset not a string
   5858  (how do we distinguish an attrset from a secret reference, hmm?)
   5859 
   5860 (2) we would convert it to /run/${name}/authorized_keys/ and use -U
   5861  anyway
   5862 
   5863 [done] - make ssh service accept keys as a param, use -U to point dropbear at them
   5864 [done] - turn replacable into a function which takes a param and returns
   5865  service or path
   5866 [done] - replacable type definition  takes a param to indicate the "underlying"
   5867 type: i.e. an attr can be replacable int or replacable attrset, not
   5868 just replacable string
   5869 [done] - destructure args in ssh.nix
   5870 [done] - write fennel script that watches a secret ref and writes authorized
   5871 keys when it changes
   5872 [done] - update ssh service to start the watcher instead of constructing key files using echo
   5873 
   5874 Sun Aug 25 19:20:56 BST 2024
   5875 
   5876 5) other sources
   5877 - local filesystem
   5878 - local filesystem with tang unlocking
   5879 
   5880 should we use a json here, or nested directories like the outputs directly?
   5881 I think json, then there's a single file to encrypt
   5882 
   5883 6) should we send authorization header?
   5884 
   5885 It's a form of protection against any random MOTP getting our secrets,
   5886 but it does mean the device has to be configured with a secret as well
   5887 as an URL, Is that OK?
   5888 
   5889 7) install on rotuer
   5890 
   5891 8) docs/video
   5892 
   5893 9) we're not using luaposix on the host so maybe we can drop it in
   5894 write-fennel?
   5895 
   5896 Sun Aug 25 21:52:23 BST 2024
   5897 
   5898 It turns out that fetch-freebsd (and, therefore, http-fstree)
   5899 can fetch file: urls, so we don't need to do anything for local files
   5900 - except maybe rename that service?
   5901 
   5902 Sun Aug 25 21:55:17 BST 2024
   5903 
   5904 clevis-{en,de}crypt-tang are bash scripts that expect PATH to include
   5905 jose, curl, cat. Most of the hard work seems to be done by jose
   5906 
   5907 Should we drag in bash (and curl ...) just to run these scripts?
   5908 
   5909 most of what clevis-decrypt-tang is doing is calling jose repeatedly
   5910 to do base64 decoding and then json manipulation, then curl, then jose
   5911 again for some actual jwk stuff. I think we could mostly rewrite this
   5912 in fennel using rxi-json and fetch
   5913 
   5914 
   5915 Wed Aug 28 09:40:41 BST 2024
   5916 
   5917 we have clevis-decrypt-tang but not encrypt
   5918 
   5919 Wed Aug 28 21:36:47 BST 2024
   5920 
   5921 
   5922 new TODO
   5923 
   5924 [done, neeeds testing] 1) to finish local secrets, we need a service
   5925 and script that gets the file, decrypts it and turns it to
   5926 outputs. Easiest way is to use a temp file in /run/${name} and then
   5927 use json-to-tree: there's no extra risk to having the plaintext json
   5928 there when it's in the same place anyway as fstree
   5929 
   5930 1.5) and test the process and write some docs
   5931 
   5932 2) perhaps we should use /run/services/var/${name} instead of /run/${name}
   5933 to avoid surprise conflicts. or we could use the existing mkstate?
   5934 mkstate is setting perms 2751 and I don't know if that's important,
   5935 but we want 0700 for secrets
   5936 
   5937 [done] 3) http auth - we have netrc file support "for free", so to speak:
   5938 fetch-freebsd looks for $NETRC or $HOME/.netrc. If we put the auth
   5939 tokens in configuration, they will get embedded into the image and
   5940 this will protect against leaked http server logs but not much else.
   5941 Scenario: you have a LAN with untrusted devices on it, plus WAPs which
   5942 want to get their config from a server. If the server logs leak, other
   5943 LAN users still can't use the config URL to fetch your PPP auth data.
   5944 
   5945 I think it just comes down to docs/video now
   5946 
   5947 
   5948 -=----
   5949 
   5950 docs!
   5951 
   5952 to cover:
   5953 
   5954 - outputs
   5955   - what for
   5956   - how to read?
   5957     - one-off read in shell
   5958     - monitoring in fennel
   5959   - how to write
   5960 
   5961 - secrets
   5962   - sources
   5963     - https
   5964     - local/tang
   5965   - supported services/attributes
   5966     - how to add a new attribute
   5967     - how to add a service
   5968   - how it works (see outputs)
   5969 
   5970 
   5971 think this is mostly to go in Configuration. Is there anything for Admin?
   5972 
   5973 
   5974 
   5975 Sat Aug 31 17:52:10 BST 2024
   5976 
   5977 Still having trouble with tangc, which I think is just poor coding in
   5978 popen2.  Hard to test it without access on loaclhost to the tangd on
   5979 bordervm
   5980 
   5981  - use a hostname instead of an ip address
   5982  - set the hostname somehow on loaclhost
   5983     (actually we could just hardcode the url in tangc.fnl)
   5984  - export 7654 in qemu somewhow
   5985 
   5986 Mon Sep  2 21:49:05 BST 2024
   5987 
   5988 TODO - Things we haven't done yet, ideas to consider
   5989 
   5990 [done] 1) improve popen2, maybe using coroutines for proper async chat
   5991 
   5992 2) allow on-device not-in-store netrc so it could be kept in 0700.
   5993 Could just do authFile = "/mnt/store/blah"
   5994 
   5995 [done] 3) we're not using luaposix on the host so maybe we can drop it in
   5996 write-fennel?
   5997 
   5998 [done] 4) add nodefaultroute to default ppp-options
   5999 
   6000 [done] 5) implement if-modified-since in json-to-fstree
   6001 
   6002 6) clean up some copy-paste (e.g. literal_or_output or whatever we call it)
   6003 - [done] ppp variants are consolidated, but there's still more to do here
   6004 
   6005 7) remove references to kexecboot
   6006 
   6007 8) performance testing
   6008 
   6009 9) revive ax3200 port and fix ubifs
   6010 
   6011 10) rebuild our wifi APs and lenscap to use levitate and outboard secrets
   6012 
   6013 11) [outside scope] secrets server on arthur, and oidc too?
   6014 
   6015 12) remove errors from ersatz coldplug
   6016 
   6017 13) teach anoia.svc how to write/remove .lock and state
   6018 
   6019 14) log kernel messages
   6020 
   6021 15) log shipping to something useful
   6022 
   6023 16) standardise error messages in fennel. using assert() is not good
   6024 for errors like "the file is missing or can't be opened" because
   6025 the backtrace is voluminous and usually inaccurate
   6026 
   6027 we could have something like check-ok which looks for the
   6028 common multiple-return (nil errmsg) pattern, we'd like a similar
   6029 one for the lualinux (nill errno) pattern.
   6030 
   6031 17) fix with nixpkgs unstable
   6032 
   6033 Wed Sep  4 21:45:07 BST 2024
   6034 
   6035 blurb for audit:
   6036 
   6037 Liminix is a Linux/Nix-based OS that can be flashed to consumer WiFi
   6038 routers of the kind that OpenWrt usually runs on (usually small MIPS
   6039 or ARM SBCs). Its USP is that because it's based on Nix, the
   6040 configuration of your device is based on a text file: there's no GUI
   6041 or other imperative interface allowing you to make changes that you
   6042 will forget you did six months later and have to recreate when you
   6043 update to a new version of the system.
   6044 
   6045 tl;dr C, nftables, Lua (Fennel even better), shell, Nix. No specific
   6046 timeline from my end (unless nlnet have told you otherwise). IMO,
   6047 emphasis on network vulnerabilities rather than anything involving local
   6048 escalation: nobody is expected to be logged in locally except for
   6049 maintenance purposes in which case they're trusted by definition.
   6050 
   6051 If you want to start by seeing it running, unless you have a
   6052 supported device then your best bet would be to build it for Qemu
   6053 <https://www.liminix.org/doc/tutorial.html#running-in-qemu>.  It boots
   6054 to a root console shell (there is no password on the serial console
   6055 because if you have that level of physical access on a real device
   6056 it's game over anyway) so take a look at the process list and
   6057 filesystem and generally poke around. The filesystem is read-only
   6058 unless you configure it otherwise.
   6059 
   6060 
   6061 To do a "static" audit: a rough breakdown of the contents, by volume, would look like this:
   6062 
   6063 1) 95% of it is packages in the Nix package system (and the Linux
   6064 kernel).  Some of the packages are built with different compilation
   6065 options to produce smaller output, and in a few cases I've patched
   6066 them, so someone with C experience might be suited to look at those
   6067 patches.
   6068 
   6069 ```
   6070 [dan@loaclhost:~/src/liminix]$ find pkgs/ -name \*.patch
   6071 pkgs/kernel/phram-allow-cached-mappings.patch           # relevant to dev devices not production
   6072 pkgs/kernel/mips-malta-fdt-from-bootloader.patch        # for qemu only
   6073 pkgs/kernel/cmdline-cookie.patch
   6074 pkgs/dropbear/add-authkeyfile-option.patch
   6075 pkgs/u-boot/0002-virtio-init-for-malta.patch            # only used in tests
   6076 pkgs/u-boot/0001-add-ubifs-to-boot-targets.patch        # only used in tests
   6077 pkgs/xl2tpd-exit-on-close.patch
   6078 pkgs/qemu/arm-image-friendly-load-addr.patch            # only used in tests
   6079 pkgs/kernel-backport/gentree-writable-outputs.patch     # unused
   6080 pkgs/openwrt/make-mtdsplit-jffs2-endian-agnostic.patch
   6081 pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch    # can be removed
   6082 pkgs/kexec-map-file.patch                               # can be removed
   6083 ```
   6084 
   6085 dropbear (ssh) and xl2tpd (l2tp) are network-accessible. The kernel
   6086 is a high-impact target, but cmdline-cookie.patch is the only "production"
   6087 patch there so hopefully easy to review
   6088 
   6089 Significant packages with custom config options:
   6090 
   6091 * hostapd (configured for libtommath, internal TLS)
   6092 * nftables (--with-mini-gmp)
   6093 * openssl "no-threads" and patches to Configure to build on MIPS
   6094 
   6095 My assumption with all of these is that the package authors wouldn't
   6096 provide these as configuration knobs if they weren't reasonably confident
   6097 they work as advertised, but I am willing to hear otherwise.
   6098 
   6099 2) the device has a firewall using nftables. The user gets to choose
   6100 their firewall rules, but the default ruleset
   6101 https://gti.telent.net/dan/liminix/src/branch/main/modules/firewall/default-rules.nix
   6102 is based on RFC 6092 for IPv6 and "received wisdom" for IPv4: I would
   6103 very much like a second pair of eyes on this.
   6104 
   6105 3) Code which is original to Liminix: as far as possible I've used a
   6106 high-level language (Fennel, which is a Lisp syntax that transpiles to
   6107 Lua) for "original" development. There is one C package
   6108 (pkgs/preinit) and some C glue to expose interfaces to Lua.
   6109 
   6110 None of the original code listens to the network (except Unix-domain
   6111 sockets). At least, it was never intended to :-)
   6112 
   6113 Highlights:
   6114 
   6115 pkgs/devout : fills the same role as udev (listens to a kernel socket
   6116  and a unix domain socket)
   6117 
   6118 pkgs/json-to-fstree : does HTTP GET and POST requests, using a port of the
   6119 FreeBSD libfetch code (see pkgs/fetch-freebsd)
   6120 
   6121 pkgs/tangc : is a transliteration from bash script to Fennel of
   6122 https://github.com/latchset/clevis/blob/master/src/pins/tang/clevis-decrypt-tang
   6123 and
   6124 https://github.com/latchset/clevis/blob/master/src/pins/tang/clevis-encrypt-tang
   6125 
   6126 I call this one out specially because it's crypto-adjacent, but all the
   6127 actual cryptography happens in "jose" which it invokes as a subprocess
   6128 
   6129 pkgs/min-copy-closure contains some shell scripts which leverage cpio
   6130 and ssh to update a running device over the network. My shell
   6131 scripting is probably worse than my C, so take a look
   6132 
   6133 4) there is a mechanism to configure the device's secrets (PPP
   6134 password, ssh keys, etc) by fetching a JSON file from an HTTPS server,
   6135 and then generating configuration files for the various services that
   6136 use those secrets. This is mostly Fennel (so, Lua)
   6137 
   6138 
   6139 5) the init/service supervision system is based on s6/s6-rc (again, C
   6140 software). I don't know if this has ever had an external audit, but to
   6141 my eyes it looks like it's been written with security in mind.
   6142 
   6143 Thu Sep  5 10:12:11 BST 2024
   6144 
   6145 if-modified-since and fenceposts ...
   6146 
   6147 we set the mtime of "." to last-modified on retrieve. what resolution
   6148 is the timestamp? empirically (using stat(1)), tmpfs seems to have
   6149 sub-second resolution, so no loss of data
   6150 
   6151 Thu Sep  5 11:15:24 BST 2024
   6152 
   6153 how do we do deadlock-free popen2? need to use select or poll
   6154 on the input and output fds, and read/write a chunk when one of them is ready
   6155 
   6156 (subprocess ["/usr/games/advent" "advent"]
   6157   {
   6158     :on-stdout #(print (ll.read %1))
   6159     :on-stderr #(print "ERR" (ll.read %1))
   6160     :on-stdin #(ll.write %1 "go north\n")
   6161   })
   6162 
   6163 for send/expect things, a single callback would be preferable if
   6164 it has a reason it's being called
   6165 
   6166 (subprocess ["/usr/games/advent" "advent"]
   6167   (fn talk [stream fd]
   6168     (match stream
   6169       :out (print (ll.read fd))
   6170       :err (print "ERR" (ll.read fd))
   6171       :in (ll.write %1 "go north\n"))))
   6172 
   6173 because it can be hooked up to a coroutine. The coroutine is then
   6174 responsible for doing things in the right order to avoid letting buffers
   6175 fill up - probably this is just a matter of dealing with the
   6176 subprocess output before sending it more that it can choke on
   6177 
   6178 wat about partial writes? the coroutine is presumably keeping some
   6179 kind of state so it can check the return of ll.write when it updates that
   6180 state
   6181 
   6182 
   6183 Fri Sep  6 19:57:37 BST 2024
   6184 
   6185 video editing
   6186 
   6187 * there are ppp credentials onscreen at 13:00
   6188 
   6189 * should finish at 33:00
   6190 
   6191 
   6192 Sat Sep  7 22:21:12 BST 2024
   6193 
   6194 what is causing these messages?
   6195 
   6196 @400000000001620127a096b3 watch-for-modem-modeswitch /nix/store/4q3swc0mg28ja30anap4id3gics3h7fk-lua-tty-mips-unknown-linux-mus
   6197 l/bin/lua: ...lr-uevent-watch-mips-unknown-linux-musl/bin/uevent-watch:4: unexpected symbol near '/'
   6198 @400000000001620127a0ec7e watch-for-modem-modeswitch stack traceback:
   6199 @400000000001620127a11c42 watch-for-modem-modeswitch    [C]: in function 'dofile'
   6200 @400000000001620127a14dec watch-for-modem-modeswitch    (command line):1: in main chunk
   6201 @400000000001620127a41b1c watch-for-modem-modeswitch    [C]: in ?
   6202 @
   6203 
   6204 Sun Sep  8 10:15:56 BST 2024
   6205 
   6206 If we could produce logs in JSON then we could push them to zinc (or
   6207 elasticsearch, which has the same api). We'd like fields for
   6208 timestamp, message, pid, host.
   6209 
   6210 * we can add host when we post to elasticsearch,  no need to repeat it
   6211 on every field
   6212 
   6213 * there is no (sensible) way to get the pid of the other end of a pipe.
   6214 But we could print it from the sender before execing the process. But then
   6215 it'll only appear once instead of every entry. Maybe we could log the
   6216 logger pid as well, then we can correlate
   6217 
   6218 TBH given that we already have to process the log lines to get them
   6219 into zinc, and that we already can unambiguously parse the log line
   6220 (provided we disallow whitespace in the service name, and we mandate
   6221 that the message is always the final field) there's not much value in
   6222 producing a different json.
   6223 
   6224 Actually the logger pid probably won't help us tell when the service
   6225 has been restarted, because the logger won't be restarted at the time
   6226 time due to fdholder stuff
   6227 
   6228 so perhaps there are no logging changes we can easily/reasonably make
   6229 and we should just write a log processor that ships to a collector.
   6230 
   6231 - open connection to zinc (s6-tlsclient)
   6232 - send http headers
   6233 - while not eof(stdin)
   6234  - read line
   6235  - split fields
   6236  - send command, send data
   6237 
   6238 { "index" : { "_index" : "olympics" } }
   6239 {"Year": 1896, "City": "Athens", "Sport": "Aquatics", "Discipline": "Swimming", "Athlete": "HAJOS, Alfred", "Country": "HUN", "Gender": "Men", "Event": "100M Freestyle", "Medal": "Gold", "Season": "summer"}
   6240 
   6241 
   6242 we can't calculate content-length. maybe we can use chunks
   6243 
   6244 Transfer-Encoding: chunked
   6245 
   6246 size-of-chunk-in-hex CRLF
   6247 chunk-data  CRLF
   6248 
   6249 0 CRLF
   6250 CRLF
   6251 
   6252 to generate test data:
   6253 $ nix-shell -p s6 --run " sort --random-sort ~/src/liminix/THOUGHTS.txt  | head -1 | sed 's/^/servicename /g' |tr -cd '[a-z0-9 ]' |  s6-tai64n"
   6254 
   6255 Sun Sep  8 16:39:55 BST 2024
   6256 
   6257 * how do we add incz to the logging infra and configure it?
   6258 * how do we get zinc on loaclhost to be visible to test lan (port forward
   6259  on border?)
   6260 * shall we rig up a service on loaclhost so that zinc starts at boot?
   6261 
   6262 Mon Sep  9 17:58:46 BST 2024
   6263 
   6264 We can use this as a log processor. However, a log processor doesn't
   6265 ship the segment until the log writer has finished with it, therefore,
   6266 some latency is introduced.
   6267 
   6268 We can write logs to the network as they are generated. However, what if:
   6269 
   6270 - the network is not available
   6271 - the collector is not keeping up
   6272 
   6273 s6-log says "if a processor fails, s6-log will try it again after some
   6274 cooldown time.".  Laurent says "if a processor fails [if you're using
   6275 -b] then the rotation cannot happen, and s6-log will stop reading
   6276 until the processor succeeds.  Without -b, logs keep accumulating in
   6277 RAM, and s6-log may crash if it runs oom before the processor
   6278 succeeds"
   6279 
   6280 .... so, maybe we shouldn't use log processors here.
   6281 
   6282 shipping finished log segments outside of the s6-log framework is
   6283 quite straightforward. the issue is how to send the in-progress log.
   6284 Challenges
   6285 
   6286 - if we are sending the in-progress log, how _not_ to resend all the
   6287 same entries when the segment is rotated
   6288 - how do we know when the segment is rotated and should start reading
   6289 the new file
   6290 
   6291 Maybe
   6292 
   6293 1) we have a logshipper service that listens on a unix socket
   6294 2) s6-log is hooked to the logshipper-client logger, which checks
   6295  for the unix socket and only writes data to it if it exists.
   6296  Probably it should check periodically for the socket to exist
   6297  and not just try it on every write
   6298  (Would be good if it could tell whether the socket had a
   6299  listener or not. Maybe abstract sockets)
   6300 
   6301 
   6302  (and also writes to stdout so the s6 logging chain is unbroken)
   6303 3) when logshipper is ready, it reads all past log entries whose
   6304  timestamps are from before when it started, and writes them.
   6305  and/or it could write a cookie to the log, then it would know
   6306  to stop reading the logs when it encounters its own cookie
   6307 
   6308 Mon Sep 16 19:54:35 BST 2024
   6309 
   6310 incz won't work as-is because it uses stdin/stdout for communicating
   6311 with http and reads the logs from a filename.  unless we make it use
   6312 /proc/self/fd/3 for the filename? Even then, ideally we kind of want
   6313 to adapt it for streaming
   6314 
   6315 Wed Sep 18 18:23:38 BST 2024
   6316 
   6317 we can run
   6318 
   6319 socat tcp-listen:19612,reuseaddr,fork | s6-log -b /var/log/clients
   6320 
   6321 on the log collection host (or use openssl-listen if you're going to set up ssl certs)
   6322 
   6323 then our logshipper program can basically be "open socket and cat to s6-tcpclient" (though it would be better if we can add the hostname in the process)
   6324 
   6325 let's make the logging script a config option
   6326 
   6327 
   6328 pipeline { s6-ipcserver -1 /run/uncaught-logs/shipping }
   6329 pipeline { s6-tcpclient loghost:19612 }
   6330 fdmove -c 1 7
   6331 cat
   6332 
   6333 Wed Sep 18 20:32:54 BST 2024
   6334 
   6335 s6-log will create its directory but the parent must exist. incidentally,
   6336 putting /run/uncaught-logs in pseudofiles is pointless because /run is a
   6337 mountpoint
   6338 
   6339 ip addr add 10.0.2.15/24 dev lan
   6340 
   6341 s6-rc -d change sshd; s6-rc -u change sshd;
   6342 
   6343 Sun Sep 22 21:13:15 BST 2024
   6344 
   6345 This works for the collector (but note that it collects logs from
   6346 *anywhere* that can write to that port, so please firewall responsibly)
   6347 
   6348 
   6349   systemd.services."s6-log-collector" = {
   6350     after = [ "network.target" ];
   6351     wantedBy = [ "multi-user.target" ];
   6352     serviceConfig = {
   6353       Type = "exec";
   6354       WorkingDirectory = "/var/log";
   6355       ExecStart = ''
   6356         ${pkgs.bash}/bin/sh -c "${pkgs.socat}/bin/socat tcp4-listen:17345,reuseaddr,fork stdout | ${pkgs.s6}/bin/s6-log -b /var/log/remote"
   6357       '';
   6358     };
   6359   };
   6360 
   6361 
   6362 Tue Sep 24 18:14:42 BST 2024
   6363 
   6364 "Raw" TCP is not the ideal transport for logs because I don't want the
   6365 whole internet able to write to my log server, and writing
   6366 only-from-the-LAN iptables rules is messy with a gazillion ipv6
   6367 addresses to account for.
   6368 
   6369 . SSL with client certificates would be nice, but there is the issue
   6370 of how to get the private key onto the device and sign it. My idea is
   6371 
   6372 1) device generates a private key on first boot (or every boot, if no
   6373 persistent storage). Private key includes some field with a value that
   6374 was set at build time (PSK, effectively)
   6375 
   6376 2) there is an API-driven CA signing thingy that the client can use to
   6377 get a cert based on their key. It checks the field for the presence
   6378 of the PSK. It should probably expose HTTPS only so that the client
   6379 can be sure it's getting signed by the correct CA
   6380 
   6381 
   6382 3) the log collector refuses connections unless the client is signed by the
   6383 local CA
   6384 
   6385 This is quite a lot of work insofar as it would appear to require
   6386 writing the CA.
   6387 
   6388 We could alternatively do something much more ad hoc where the client
   6389 just writes the PSK to the server when it opens the stream, before
   6390 sending any data. We'd have to write the server end, then, instead of
   6391 just using socat - but that is probably less work than an API-driven CA.
   6392 On the other hand, TLS logs would also be encrypted which is a good thing
   6393 if the LAN is not trusted.
   6394 
   6395 Sat Sep 28 16:04:15 BST 2024
   6396 
   6397 OK, so we wrote the CA.
   6398 
   6399 To do HTTPS on the client we need
   6400 
   6401 1) to generate a csr
   6402 2) to https it to the server
   6403 3) store the generated thingy as a service output
   6404 
   6405 looking at x86-64 sizes for ballpark
   6406 
   6407 -r-xr-xr-x 1 root root 987K Jan  1  1970 /nix/store/s45wy1ssim1dkxzligx09xjp4n0668i2-openssl-3.0.14-bin/bin/openssl
   6408 -r-xr-xr-x 1 root root 263K Jan  1  1970 /nix/store/z28bxdnsw2gr1xwx7qj6px9iz5sr84i9-lua-5.3.6-env/lib/lua/5.3/_openssl.so
   6409 
   6410 suggesting that we'd use _less_ disk doing the whole thing in lua than
   6411 
   6412 Sun Sep 29 10:20:49 BST 2024
   6413 
   6414 We need luaossl support for setting attributes in a CSR
   6415 
   6416 https://www.rfc-editor.org/rfc/rfc2986#page-5
   6417 
   6418    Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
   6419 
   6420    CRIAttributes  ATTRIBUTE  ::= {
   6421         ... -- add any locally defined attributes here -- }
   6422 
   6423    Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
   6424         type   ATTRIBUTE.&id({IOSet}),
   6425         values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
   6426    }
   6427 
   6428 I don't understand this 100% but it looks like the raw data is _not_
   6429 the same format as an x509 attribute. See e.g.
   6430 https://github.com/golang/go/commit/e78e654c1de0a7bfe0314d6954d42b046f14f1bb#diff-a789286d7e257f148c437404f8cf5d3379688597381ff13352e62ac406be295aL1712
   6431 in support of my hypothesis (background: iiuc, "critical" is a boolean flag,
   6432 but x509 attributes aren't allowed to be booleans)
   6433 
   6434 https://en.wikipedia.org/wiki/Certificate_signing_request
   6435 
   6436   388:d=2  hl=2 l=  35 cons:   cont [ 0 ]
   6437   390:d=3  hl=2 l=  33 cons:    SEQUENCE
   6438   392:d=4  hl=2 l=   9 prim:     OBJECT            :challengePassword
   6439   403:d=4  hl=2 l=  20 cons:     SET
   6440   405:d=5  hl=2 l=  18 prim:      UTF8STRING        :loves labours lost
   6441   425:d=1  hl=2 l=  13 cons:  SEQUENCE
   6442   427:d=2  hl=2 l=   9 prim:   OBJECT            :sha256WithRSAEncryption
   6443 
   6444 
   6445 (csr:getAttribute "challengePassword")
   6446 (csr:getAttributeNames)
   6447 (csr:setAttribute "challengePassword" :IA5STRING ["loves labours lost"])
   6448 
   6449 how do we know the asn1 type of the attribute values? it looks like they're
   6450 defined by the object: see e.g. https://www.rfc-editor.org/rfc/rfc2985#page-16
   6451 
   6452    A challenge-password attribute must have a single attribute value.
   6453 
   6454    ChallengePassword attribute values generated in accordance with this
   6455    version of this document SHOULD use the PrintableString encoding
   6456    whenever possible.  If internationalization issues make this
   6457    impossible, the UTF8String alternative SHOULD be used.  PKCS #9-
   6458    attribute processing systems MUST be able to recognize and process
   6459    all string types in DirectoryString values.
   6460 
   6461 crypto/asn1/tbl_standard.h:    {NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0},
   6462 include/openssl/asn1.h.in:# define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING)
   6463 
   6464 I assume there's something in openssl that will do lookups in this table
   6465 to give us the type for the oid, then maybe something in luaossl that
   6466 would lua-ize it?
   6467 5
   6468 
   6469 or we could put that burden on the caller, as x509.name:add does
   6470 
   6471 Sun Sep 29 20:46:16 BST 2024
   6472 
   6473 
   6474 OBJ_txt2nid("challengePassword"); works with short/long names
   6475 
   6476 the get call is complicated because there can be multiple
   6477 attributes with the same type. There probably aren't but ...
   6478 
   6479 (csr:getAttribute "challengePassword") => multivals attr, index
   6480 
   6481 (csr:getAttribute "challengePassword" index) => multivals attr, index
   6482 
   6483 (csr:addAttribute "challengePassword" :IA5String ["loves labours"])
   6484 
   6485 (csr:clearAttribute index)
   6486 
   6487 
   6488 Tue Oct  1 21:55:25 BST 2024
   6489 
   6490 on server, we need to reconfigure socat to give it our CA cert and
   6491 expect peer to authenticate
   6492 
   6493 on client, I am not sure if we can persuade s6-tlsclient to use the same
   6494 file for cert and private key.  perhaps certifix-client could write
   6495 two separate files with --out-key and --out-certificate
   6496 
   6497 
   6498 CAFILE=ca.crt KEYFILE=client.key CERTFILE=client.crt s6-tlsclient -k localhost -y -v localhost 19612 socat 'fd:6!!fd:7'  -
   6499 
   6500 
   6501 socat ssl-l:19612,reuseaddr,fork,cert=server-combined.pem,cafile=ca.crt  stdout
   6502 
   6503 suggest creating /var/lib/s6-log-collector/{private,cert} on loaclhost
   6504 wherein we keep the server and ca keys, then socat and the signing
   6505 server can both see them
   6506 
   6507 
   6508 ip addr add 10.0.2.15/24 dev lan
   6509 
   6510 Sat Oct  5 22:35:41 BST 2024
   6511 
   6512 We had it working in a VM, and the service is installed on loaclhost
   6513 
   6514 TODO
   6515 
   6516 [done] 1) make a module-based service for client-cert
   6517 caCertificateFile
   6518 secretFile
   6519 subject
   6520 url
   6521 
   6522 [done] 2) make the shipping service a consumer-for
   6523 
   6524 [not by much] 3) can we reduce the verbiage in the shipping service somehow?
   6525 
   6526 4) rebuild an actual device with all this stuff
   6527 
   6528 Tue Oct  8 23:50:00 BST 2024
   6529 
   6530 idea: create outputs.update which builds a systemConfiguration and
   6531 also a result/install.sh which does  min-copy-closure and
   6532 restart-services as per liminix-rebuild, then we don't have
   6533 to nix-shell liminix-rebuild
   6534 
   6535 nix-build ../liminix/ -I liminix-config=hosts/rotuer.nix --argstr deviceName turris-omnia -A outputs.update-system  -o rotuer && ./rotuer/install.sh
   6536 
   6537 this would make it much more straightforward to build a bunch of hosts
   6538 using a Makefile
   6539 
   6540 idea 2: when a configuration contains levitate, something similar
   6541 but necessarily more "manual" to do the analogous thing
   6542 
   6543 
   6544 Sun Dec 15 18:55:55 GMT 2024
   6545 
   6546 Where we left off with this, rotuer was crashing randomly or failing
   6547 to boot every time we tried to add log shipping, which is not very
   6548 ideal. I started doing something with logging to /dev/pmsg0
   6549 (CONFIG_PSTORE_PMSG) but I think (there seems not to be anything
   6550 written down :-( ) that the gl-ar750 kernel needs it added to kconfig and device tree
   6551 
   6552 https://wiki.postmarketos.org/wiki/User:Knuxify/Enabling_pstore_and_ramoops
   6553 
   6554 we could add a new hardware.dts.dtsi = [] option so that any module
   6555 could add a new chunk of dts. (Ideally we'd call it `includes`
   6556 but that conflicts with the existing use of `includes` to specify
   6557 search path. Maybe rename?)
   6558 
   6559 would we ever use it except in a hardware device definition?
   6560 (Or user config?) I guess if we were consistent with names
   6561 then we could set up nodes in the device file with status="disabled"
   6562 and enable them in the module, except that dt doesn't consistently
   6563 use status and in fact there isn't one for reserved-memory
   6564 
   6565 we could use global config to enable pstore_msg and check it in
   6566 the device module to enable the needed hw support
   6567 
   6568 Tue Dec 17 23:39:28 GMT 2024
   6569 
   6570 I think we can just stick a tee in the fallback logger pipeline that
   6571 writes to /dev/pmsg0
   6572 
   6573 Need to check it's a circular buffer
   6574 
   6575 do we want to do anything about recovering the log on boot?
   6576 - we could just copy it to /run/log
   6577 - if we have backfilling for shipped logs (we don't yet)
   6578   then we might want to ship it - but that may result in duplicate
   6579   logs if some of it was shipped before the crash
   6580 
   6581 perhaps we should truncate pmsg0 on orderly shutdown? or maybe it's
   6582 good to see the late shutdown logs.
   6583 
   6584 Thu Dec 19 13:40:39 GMT 2024
   6585 
   6586 although we have PSTORE_foo in the omnia kconfig, I think this might
   6587 be just because I copied it from RT3200
   6588 
   6589 Thu Dec 19 14:15:43 GMT 2024
   6590 
   6591 Omnia is not in ci.nix, and it's not trivial to add it because there
   6592 is no output in the ci.nix configuration that makes sense for omnia.
   6593 
   6594 ... OK, fixed by adding system-configuration as an independent module
   6595 and importing in device config
   6596 
   6597 Thu Dec 19 21:59:47 GMT 2024
   6598 
   6599 The build-system shell script in outputs.systemConfiguration
   6600 is ugly and requires we do bad things to avoid sucking build
   6601 system stuff into the config
   6602 
   6603 I propose we make it a separate derivation.
   6604 
   6605 But first maybe we could improve some names
   6606 
   6607 Sun Dec 22 14:23:02 GMT 2024
   6608 
   6609 MT7622> echo $boot_default
   6610 if env exists flag_recover ; then else run bootcmd ; fi ; run boot_recovery ; setenv replacevol 1 ; run boot_tftp_for
   6611 ever
   6612 MT7622> echo $bootcmd
   6613 if pstore check ; then run boot_recovery ; else run boot_ubi ; fi
   6614 MT7622> echo $boot_ubi
   6615 ubi part ubi && run boot_production ; run boot_recovery
   6616 MT7622> echo $boot_production
   6617 led $bootled_pwr on ; run ubi_read_production && bootm $loadaddr#$bootconf ; led $bootled_pwr off
   6618 MT7622> echo $ubi_read_production
   6619 ubi read $loadaddr fit && iminfo $loadaddr && run ubi_prepare_rootfs
   6620 MT7622> echo $ubi_prepare_rootfs
   6621 if ubi check rootfs_data ; then else if env exists rootfs_data_max ; then ubi create rootfs_data $rootfs_data_max dynamic || ubi create rootfs_data - dynamic ; else ubi create rootfs_data - dynamic ; fi ; fi
   6622 MT7622> echo $bootconf
   6623 config-1
   6624 MT7622> run boot_ubi
   6625 UBI partition 'ubi' already selected
   6626 No size specified -> Using max size (126976)
   6627 Read 126976 bytes from volume fit to 0000000048000000
   6628 
   6629 ## Checking Image at 48000000 ...
   6630 Unknown image format!
   6631 No size specified -> Using max size (7491584)
   6632 Read 7491584 bytes from volume recovery to 0000000048000000
   6633 ## Loading kernel from FIT Image at 48000000 ...
   6634    Using 'config-1' configuration
   6635    Trying 'kernel-1' kernel subimage
   6636      Description:  ARM64 OpenWrt Linux-6.6.45
   6637 
   6638 Sun Dec 22 17:39:56 GMT 2024
   6639 
   6640 From the output above it looks like the device I have plugged in has
   6641 an openwrt "recovery" image but not a "production" image
   6642 
   6643 It also looks like it will be quite hard work to persuade it to boot
   6644 from usb or anything. It doesn't have any of the extlinux stuff
   6645 but it does have uefi for what that's worth
   6646 
   6647 default boot_production command reads a ubi volume called 'fit' and
   6648 calls bootm on what it finds
   6649 
   6650 we could define boot_production to ubifsmount liminix; ubifs load
   6651 <addr> <filename> (which is a fit) and bootm it. *presumably* we could
   6652 do this from the openwrt recovery image
   6653 
   6654 but could we install the whole system using said recovery image?  I
   6655 expect we could do, it only requires getting a tarball onto it and
   6656 unpacking it
   6657 
   6658 however, extlinux is not going to be helpful
   6659 (actually it might be a bit, if we ask it to write the fit as
   6660 well as/instead of the individual files)
   6661 
   6662 maybe we need separate concepts of "the filesystem contains
   6663 stuff we need for boot" and "the stuff we need is the stuff
   6664 that extlinux needs"
   6665 
   6666 each bootloader makes an output called bootfiles, and
   6667 the bootablerootdir output copies from bootfiles
   6668 
   6669 Mon Dec 23 18:28:50 GMT 2024
   6670 
   6671 it might be worth moving ubi option decls into the hardware module, if
   6672 they're hardware-dependent
   6673 
   6674 Tue Dec 24 16:14:50 GMT 2024
   6675 
   6676 Where next?
   6677 
   6678 a config for haproxy would be good
   6679 
   6680 > a connection or request arrives on a frontend, then the
   6681 information carried with this request or connection are processed, and
   6682 at this point it is possible to write ACLs-based conditions making use
   6683 of these information to decide what backend will process the request.
   6684 
   6685 http://docs.haproxy.org/3.1/intro.html#3.4.4
   6686 
   6687 listen foo
   6688 	bind :443
   6689 
   6690 frontend foo
   6691 	mode tcp
   6692 
   6693 Thu Dec 26 14:27:26 GMT 2024
   6694 
   6695 What's the plan?
   6696 
   6697 1) build the updater target for rotuer
   6698 2) ssh forward through bordervm to install it
   6699 3) carve the ngix sni proxy into examples/module-sniproxy
   6700   with a fat warning comment
   6701 3.5) should  we add the examples to ci?
   6702 4) see if it builds
   6703 5) using curl on bordervm, see if it forwards
   6704 5000) swap the real rotuer hardware
   6705 
   6706 
   6707 Sun Dec 29 18:22:42 GMT 2024
   6708 
   6709 To make sniproxy work it needs dns, which means it needs an upstream.
   6710 But if we move the bordervm cable from lan to wan, we won't be able to
   6711 rebuild over ssh unless it's sufficiently unbroken for pppoe to be working
   6712 
   6713 ... unless we add a "management" address to the wan interface along with pppoe
   6714 
   6715 to permit wan stuff through the firewall, now that we've fixed the
   6716 firewall :embarrassed:, do
   6717 
   6718 /nix/store/*nftables*/bin/nft insert rule table-ip input-ip4 position 19  iifname "wan" jump incoming-allowed-ip4
   6719 
   6720 What else do we need to try rt3200 as prod rotuer?
   6721 
   6722 - pstore logging
   6723 - log shipping (maybe via wan to bordervm for now)
   6724 - enable sniproxy module
   6725 
   6726 zcat /proc/config.gz  | grep PSTORE
   6727 
   6728 Tue Dec 31 22:45:33 GMT 2024
   6729 
   6730 /nix/store/i1khbsqpyx020xrhvfbdazc1bnmirc72-kernel-aarch64-unknown-linux-musl-modulesupport/vmlinux
   6731 
   6732 
   6733 these 3 derivations will be built:
   6734   /nix/store/fvxrvyx64cm86cc4na0584qj9xw6s406-kernel-aarch64-unknown-linux-musl.drv
   6735   /nix/store/ksg93bd8x2z1xpfmj24ixm2srg547mjx-dtb-aarch64-unknown-linux-musl.drv
   6736   /nix/store/n33ij1npzwjmlsw23sz6yhyrh9hgxwaw-kernel.image-aarch64-unknown-linux-musl.drv
   6737 building '/nix/store/fvxrvyx64cm86cc4na0584qj9xw6s406-kernel-aarch64-unknown-linux-musl.drv'...
   6738 zcat /proc/config.gz  | grep PSTORE
   6739 
   6740 we think tftpboot works (check!)
   6741 build the FIT from the updater target with squashfs added in rotuer.nix
   6742 boot it with tftp by copy-pasting the boot.scr and changing it
   6743 
   6744 setenv serverip 10.0.0.1
   6745 setenv ipaddr 10.0.0.8
   6746 tftpboot 0x4007ff28 r2/rootfs; tftpboot 0x41086f28 r2/image; tftpboot 0x4107ff28 r2/dtb
   6747  bootm 0x41086f28 - 0x4107ff28
   6748 
   6749 tftpboot works
   6750 tftpboot with outputs.uimage works
   6751 1458ed2cdeaa6bf4c02c6511a6d7369d  /nix/store/4n3jc4n7lsp73yc2ccnmgibc7079rxms-kernel.image-aarch64-unknown-linux-musl
   6752 
   6753 $ grep fit /nix/store/ihi7vski37b9ph4xcyqpabymc5nsngjd-system-configuration-aarch64-unknown-linux-musl/etc/nix-store-paths
   6754 /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit
   6755 $ md5sum /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit/fit
   6756 1458ed2cdeaa6bf4c02c6511a6d7369d  /nix/store/5jphs9mnb8hzhvwfi2z8h6cnaz6qx4y6-boot-fit/fit
   6757 
   6758 something is changing /persist/boot from a symlink to a directory and I don't know what
   6759 ... plot twist: or is it? maybe it's ubimage that makes it a directory
   6760 
   6761 rt3200 has no pmsg-size according to  dtc -I fs  /proc/device-tree/ -O dts
   6762 
   6763 should be more like
   6764 
   6765 reserved-memory {
   6766 		ramoops@03f00000 {
   6767 			compatible = "ramoops";
   6768 			reg = <0x03f00000 0x10000>;
   6769 			pmsg-size = <0x10000>;
   6770 		};
   6771 	};
   6772 };
   6773 
   6774 Wed Jan  1 14:57:35 GMT 2025
   6775 
   6776 At last I have working persistent logging.
   6777 
   6778 I think we need to do something at boot time to move the persistent logs into
   6779 the regular s6 log thing
   6780 
   6781       foreground {
   6782         redirfd -w 1 /run/prior-boot2
   6783         elglob file /sys/fs/pstore/* cat $file
   6784       }
   6785 
   6786 Thu Jan  2 14:31:11 GMT 2025
   6787 
   6788 to change to a previous "generation" we could run any of
   6789 "/nix/store/*system-configuration*/bin/install /mnt" from a rescue
   6790 system. It would populate /boot and bin/activate
   6791 
   6792 supposing we are in such a rescue system, how do we find *which*
   6793 system-configuration is the one we want to revert to? The derivation
   6794 should be pure, so if we're going to timestamp anything we have to do
   6795 that in the imperative step i.e. update.sh
   6796 
   6797 perhaps a symlink from /persist/configuration/yyyymmddtmmhhss -> /nix/store/eeee-blah
   6798 
   6799 
   6800 Thu Jan  2 23:38:59 GMT 2025
   6801 
   6802 Stuff we should tidy up:
   6803 
   6804 1) all devices to set credible default output, rootfs, etc
   6805 2) expunge remaining references to kexecboot
   6806 3) dynamic uid assigment for users
   6807 4) lessen logging noise from firewall
   6808 5) update.sh --fast sends wlan services for a spin
   6809 
   6810 
   6811 
   6812 Fri Jan  3 16:05:10 GMT 2025
   6813 
   6814 * build actual rotuer config and install on rt3200
   6815 * find usb ethernet dongle for laptop
   6816 * plug it in?
   6817 
   6818 Sat Jan  4 15:32:03 GMT 2025
   6819 
   6820 didn't work so well, because the installer version is coupled with the
   6821 dtb and the dtb can't be upgraded without upgrading the kenrel
   6822 
   6823 kernel 6.6.67 builds and boots but seems to have no wired ethernet.
   6824 looking through the openwrt config changes ...
   6825 
   6826 +CONFIG_MTD_UBI_NVMEM=y
   6827 +CONFIG_NVMEM_BLOCK=y
   6828 +CONFIG_NVMEM_LAYOUT_ADTRAN=y
   6829 +CONFIG_PHYLIB_LEDS=y
   6830 +CONFIG_MTK_REGULATOR_COUPLER=y
   6831 +CONFIG_FW_LOADER_SYSFS=y
   6832 
   6833 
   6834 Sun Jan  5 12:58:52 GMT 2025
   6835 
   6836 We are running with rt3200 and everything appears to work :-)
   6837 
   6838 Sun Jan  5 20:34:18 GMT 2025
   6839 
   6840 what customization do we want from the firewall?
   6841 
   6842  - what's allowed wan->lan
   6843  - what's allowed lan->wan
   6844  - which dropped packets get logged or don't
   6845 
   6846 plus fix whatever it was RoS found
   6847 plus stop hardcoding the interface names
   6848 
   6849  Q: if pppd _makes_ an interface, how do we know what the name of it
   6850  is going to be before it's up and passing packets so that we can
   6851  have the firewall active before it starts
   6852 
   6853  or could we have ppp service install a "drop everything" firewall
   6854  before it starts? what if there's more than one upstream interface,
   6855  they shouldn't wipe each other out
   6856 
   6857  so can we have a "default deny" firewall in which every allowed flow
   6858  is qualified by the interface name, and any service that brings up an
   6859  interface is required to add firewall rules for it according to its
   6860  role
   6861 
   6862  or maybe the firewall service could watch for interfaces being added
   6863  (and removed) and update the ruleset as appropriate for the interface
   6864  role (lan, wan, dmz, management, guest, ???). but how does it know
   6865  the role based on the interface name?
   6866 
   6867 Tue Jan 14 19:33:28 GMT 2025
   6868 
   6869 each interface can add its own chain when it comes up, and then we can
   6870 figure out some way to jump to the correct chain (vmaps) based on
   6871 interface name
   6872 
   6873 % nft add map filter mydict { type ipv4_addr : verdict\; }
   6874 % nft add element filter mydict { 192.168.0.10 : drop, 192.168.0.11 : accept }
   6875 % nft add rule filter input ip saddr vmap @mydict
   6876 
   6877 _but_ we might be better off declaring static "zones" (lan, world,
   6878 dmz, guest, etc etc) with a map for each, and then replace the hardcoded
   6879 interface names with a map lookup
   6880 
   6881 % nft add map filter ifzone { type ifname : string ; }
   6882 
   6883 
   6884 zones  { type ifname: ipv4_addr\; }
   6885  ...  and presumably we also need identical maps for nat and
   6886  ...  any other chain type where we need to distinguish
   6887  ...  inside from outside
   6888 % nft add element nat porttoip { 80 : 192.168.1.100, 8888 : 192.168.1.101 }
   6889 
   6890 % nft add rule ip nat postrouting snat to tcp dport map @porttoip
   6891 
   6892 Mon Jan 20 20:32:58 GMT 2025
   6893 
   6894 1) maybe we can add a type="chain" or type="set" attribute to the
   6895 firewallgen input, then we cna have sets in the default firewall rules
   6896 
   6897 2) then we convert the default firewall rules to use sets instead of
   6898 hardcoding ifname
   6899 
   6900 3) then find a nice place to hook "new interface is available" and
   6901 add it to the appropriate zone (separately for ip4 and ip6, gah)
   6902 
   6903 4) and how do we find
   6904 
   6905 # nft add element ip table-ip lan { int }
   6906 # nft add element ip table-ip wan { ppp0 }
   6907 # nft add element ip6 table-ip6 lan { int }
   6908 # nft add element ip6 table-ip6 wan { ppp0 }
   6909 
   6910 Tue Jan 28 21:51:46 GMT 2025
   6911 
   6912 Going back and forth on the firewall stuff, in respect of where to aim
   6913 for with "general" vs "useful". Specifically, if we have hooks
   6914 every time interfaces are added/removed that
   6915 expect some specific sets to (a) exist and (b) have particular
   6916 semantics, there is necessary coupling between those hooks and the
   6917 firewall definition. So, practically speaking, the "a new interface
   6918 appears" rules need to be bundled with the firewall ruleset
   6919 
   6920 Which also means that the firewall needs to know which zone the
   6921 interface is assigned to, which is a problem if it can't tell from the
   6922 name (for example wg0 wg1 wg2 ... could be wan or lan or dmz or
   6923 anything)
   6924 
   6925 So the service that owns the interface needs to communicate "another
   6926 one for the lan zone" to the firewall and it can't do that by adding
   6927 to sets directly unless it knows what the sets are called. Implying we
   6928 need an interface between the interface service that knows "new
   6929 interface ppp7 added in wan zone" and the firewall service that knows
   6930 how to accommodate this. For extra credit this actually should be more
   6931 like pubsub: the interface shouldn't really have to know the firewall
   6932 exists.
   6933 
   6934 outputs?
   6935 
   6936 - what if each interface wrote a "zone" output and the firewall
   6937 subscribed to them? would need the firewall to know which of all the
   6938 available services were interfaces
   6939 
   6940 - a zone service that every interface in the zone depends on. it
   6941 doesn't do much in itself but it means the interface updown scripts
   6942 know a service directory where they can touch lan-zone/eth0 or
   6943 whatever. This could work.  The firewall service definition specifies
   6944 the zone services and uses inotify watcher thingies to update
   6945 interface sets when contents change.
   6946 
   6947 Wed Jan 29 17:19:24 GMT 2025
   6948 
   6949 1) make a zone service defn that can be instantiated for each zone.
   6950 it should create $output/interfaces
   6951 
   6952 2) add a `zone` attribute to interface definitions, causing
   6953 - the zone service to be added to the dependencies
   6954 - the interface "up" script to include writing to the zone/interfaces output
   6955 
   6956 2b) any other service that creates an interface (e.g. ppp) needs to also
   6957 have `zone` and do the same
   6958 
   6959 3) firewallgen to be able to make sets
   6960 
   6961 4) firewall service to watch the zone outputs
   6962 
   6963 Fri Jan 31 17:11:16 GMT 2025
   6964 
   6965 Do we need zone services? I think we could put zones in the outputs of
   6966 the firewall service?
   6967 
   6968 Sun Feb  2 20:59:56 GMT 2025
   6969 
   6970 What's the smallest first step?
   6971 
   6972  - [done] how can we make firewallgen output sets (or could we
   6973    make the firewall service tack them on afterwards)
   6974 
   6975  - make a longrun that watches its own zones output and updates the
   6976    appropriate sets
   6977 
   6978 The sticking point is that if you give the firewall `rules` instead of
   6979 `extraRules` then the longrun may or may not work depending on (1)
   6980 whether you made the zone sets; (2) whether your rules use
   6981 them. Conclusion: if you supply `rules` then you also have to say
   6982 whether you want the longrun or not. So add a param
   6983 watchForInterfaceUpdates which defaults true
   6984 
   6985 Mon Feb  3 21:12:55 GMT 2025
   6986 
   6987 the thing that updates sets has to know they exist, so the interface watcher
   6988 service must live in the firewall module
   6989 
   6990 the firewall service defn should return the firewall service after
   6991 adding the interface watcher as a dependency of it. Or: the watcher
   6992 should make the sets and then the firewall service could depend on _it_.
   6993 That would mean that the firewall service would fail if it used sets
   6994 that the watcher didn't make, is that good or bad or indifferent?
   6995 
   6996 the interface services have to know about the watcher as well in order
   6997 to write into its outputs, so it can't be hidden inside the module
   6998 
   6999 maybe the watcher service should _be_ the firewall service.
   7000 
   7001 we could add a "notify" param to an interface which would be an output
   7002 reference to (the firewall service / zones / lan ) that the interface would
   7003 write its ifname into when the service is up
   7004 
   7005 Wed Feb  5 00:14:29 GMT 2025
   7006 
   7007 another thought: the firewall service could have params to say
   7008 which interface services are in which zones
   7009 
   7010 we'd have to ensure that the interface services did not end up as
   7011 dependencies of the firewall
   7012 
   7013 then the firewall could
   7014 
   7015 - create the sets
   7016 - watch each interface service for the ifname output and add it to the right zone
   7017 
   7018 Sun Feb  9 21:33:57 GMT 2025
   7019 
   7020 nft update set @lan
   7021 
   7022 echo 'flush set table-ip lan;  add element table-ip lan { eth0,lo }' | nft -f -
   7023 
   7024 Tue Feb 11 18:30:09 GMT 2025
   7025 
   7026 outstanding for 1.0:
   7027 
   7028 1) security audit fedback
   7029 
   7030 a) ask ROS if I can ship their report, with a response doc
   7031  showing the commits that address each finding/non-finding
   7032 b) firewall rules: icmp rate limit, DNS, doc for icmpv6 packet dropping
   7033 c) look over env var inputs and parse them properly instead of
   7034   string glommeration
   7035 
   7036 2) docs:
   7037  - for each device, add "finishedness" status and link to build status
   7038  - generally read them over and spruce up
   7039  - porting guide
   7040 
   7041 3) some kconfig magic to generate minimal kconfig files so that
   7042 device modules don't end up as copy-pastes of the openwrt defconfig
   7043 
   7044 
   7045 ---
   7046 
   7047 apparently 5% of available bandwidth is a reasonable rate limit for
   7048 icmp
   7049 
   7050 % nft add rule filter input limit rate over 10 mbytes/second drop
   7051 
   7052 but nftables has no way to get interface bandwidth and indeed nor does
   7053 the device generally: the 1000Mb/s ethernet interface might be
   7054 connected to a 70Mb/s pppoe upstream and how would it know?  So the
   7055 site operator needs to say somewhere what the upstream bandwidth is.
   7056 
   7057 Sun Feb 16 22:16:29 GMT 2025
   7058 
   7059 we probably didn't need to write that service, we could have used the
   7060 thing that makes templated config files _and_ if we somehow contrive
   7061 to write the interface bandwidth as an interface output we could get
   7062 that the same way
   7063 
   7064 if only I could remember how it worked :-)
   7065 
   7066 ----
   7067 
   7068 * watch-output watches only _one_ service and is called with a list of
   7069 outputs inside that service, so not exactly what we need. we can
   7070 extend it easily enough to watch multiple services using poll() if we
   7071 can figure out the syntax we want. Luckily all the places that call it
   7072 go through modules/secrets/subscriber.nix so it's easy enough to change
   7073 existing uses
   7074 
   7075 we could do
   7076 watch-outputs -r foo /nix/store/blah/.outputs/ifname   /nix/store/eee/.outputs/ifname  ...
   7077 
   7078 or
   7079 watch-outputs -r foo /nix/store/blah:ifname   /nix/store/eee:ifname  /nix/store/eee:bandwidth
   7080 
   7081 or
   7082 
   7083 watch-outputs -r foo /nix/store/blah:ifname   /nix/store/eee:ifname:bandwidth
   7084 
   7085 which I quite like insofar as it's shorter but has no other real merit
   7086 
   7087 then we need to decide how to represent an output reference in a firewall rule.
   7088 Since each rule is basically text already, might just put the handlebars straight in
   7089 
   7090 let qq = builtins.toJSON ;
   7091 in "icmp6 limit rate over {{ tonumber(output(${qq (intf "service")}, ${qq (intf "bandwidth")})) / 20 }} bytes/second drop"
   7092 
   7093 probably we should do a separate rule for each interface in the wan zone
   7094 
   7095 Sun Feb 23 00:34:34 GMT 2025
   7096 
   7097 looks like we have no tests for anything involving watched services or subscribers,
   7098 or if we do I can't see what
   7099 
   7100 Thu Feb 27 20:47:03 GMT 2025
   7101 
   7102 - use output-template to write firewall rule file
   7103 - wrap firewall in svc.secrets.subscriber.build (c.f. e745991) with zones as
   7104    watched services
   7105 - put the handlebars in the firewall config
   7106 
   7107 we have uncommitted changes to watch-outputs that I'm relunctant to
   7108 commit until I have some way to see if they're working. the pppoe test
   7109 will check both firewall zones so _should_ start to fail with the
   7110 current watch-outputs (because only one service) and then pass when we
   7111 put the new one in
   7112 
   7113 Fri Feb 28 01:00:03 GMT 2025
   7114 
   7115 Well, it works at least well enough to pass the test. There is an awful hack
   7116 though, because nftables doesn't accept "elements = { }" as valid syntax
   7117 for a set with no elements, so we post-process the file to wipe those lines
   7118 
   7119 I wonder if we could instead create the set empty and then use the "other"
   7120 nftables format to generate commands that add the elements. If it's
   7121 all in the same file (or included files) it will continue to be atomic
   7122 
   7123 Other options
   7124 
   7125 - is the nftables json format any better? we will have to rebuild it
   7126   with json support, may be bugger
   7127 - write lua bindings to libnftables
   7128 
   7129 Fri Feb 28 23:31:06 GMT 2025
   7130 
   7131 adding json would add 76 + 88k to the image, but I think it would also
   7132 mean we have to rewrite all the default rules in json format
   7133 
   7134 
   7135 
   7136 with json
   7137 [dan@loaclhost:~/src/liminix]$ du  result/
   7138 20      result/share/doc/nftables/examples
   7139 24      result/share/doc/nftables
   7140 28      result/share/doc
   7141 12      result/share/man/man3
   7142 16      result/share/man/man5
   7143 44      result/share/man/man8
   7144 76      result/share/man
   7145 60      result/share/nftables
   7146 168     result/share
   7147 36      result/etc/nftables/osf
   7148 40      result/etc/nftables
   7149 44      result/etc
   7150 76      result/bin
   7151 8       result/include/nftables
   7152 12      result/include
   7153 8       result/lib/pkgconfig
   7154 1172    result/lib
   7155 1476    result/
   7156 
   7157 [dan@loaclhost:~/src/liminix]$ du /nix/store/l0zsvldsskiv52b4c9b21ziq5z1qr7vn-jansson-mips-unknown-linux-musl-2.14/
   7158 84      /nix/store/l0zsvldsskiv52b4c9b21ziq5z1qr7vn-jansson-mips-unknown-linux-musl-2.14/lib
   7159 88      /nix/store/l0zsvldsskiv52b4c9b21ziq5z1qr7vn-jansson-mips-unknown-linux-musl-2.14/
   7160 
   7161 without:
   7162 [dan@loaclhost:~/src/liminix]$ du  result/
   7163 20      result/share/doc/nftables/examples
   7164 24      result/share/doc/nftables
   7165 28      result/share/doc
   7166 12      result/share/man/man3
   7167 16      result/share/man/man5
   7168 44      result/share/man/man8
   7169 76      result/share/man
   7170 60      result/share/nftables
   7171 168     result/share
   7172 36      result/etc/nftables/osf
   7173 40      result/etc/nftables
   7174 44      result/etc
   7175 76      result/bin
   7176 8       result/include/nftables
   7177 12      result/include
   7178 8       result/lib/pkgconfig
   7179 1096    result/lib
   7180 1400    result/
   7181 
   7182 
   7183 Sat Mar  1 23:43:17 GMT 2025
   7184 
   7185 I don't think json is going to help because either we'd have to do
   7186 
   7187  elements = map (f: "{{ lookup(f, \"ifname\") }}") zones.${zone}
   7188 
   7189 and there would  be null elements in the places for the interfaces that don't exist
   7190 yet, or we'd have to write actual json syntax at runtime, at which point why don't
   7191 we write the trad nftables syntax instead?
   7192 
   7193 let's write a firewall .nftables file consisting of the zone set
   7194 elements plus an "include" directive for the rest of the firewall. NOTE THAT
   7195 we may still need to template the rest of the firewall if we want to have
   7196 other variables (rate limits) in it, because the rules for that need to be
   7197 inserted ahead of the rules for accepting icmp, and there's no way to
   7198 do that without
   7199 
   7200 Sun Mar  9 21:46:30 GMT 2025
   7201 
   7202 OK, we have updating firewall zones that are good neough to pass the test
   7203 (and may even work ...).  We need
   7204 
   7205 * to write a rule with a rate limit for incoming icmp6 for each interface,
   7206 capping it to 5% of the interface bandwidth
   7207 
   7208 * some place to say what the bandwidth is, which I am thinking we could do with
   7209 a passthru attribute of some kind on services
   7210 
   7211 {
   7212   run = "mdcnvdfngkj";
   7213   name = "dtret";
   7214   properties.bandwidthKbps = 80000;
   7215 }
   7216 
   7217 and insert logic in the up/run commands to copy the properties to
   7218 outputs.  Or we could use `data` or `env` directories, which means
   7219 that the properties would be there even while the service is down, if
   7220 that's a concern, but would need a different way to look them up. And
   7221 also, would we allow them to change? What if there's some kind of interface
   7222 where we _can_ interrogate the bandwidth at runtime?
   7223 
   7224 Mon Mar 10 21:00:17 GMT 2025
   7225 
   7226 The idea that occured to me at lunchtime is "what if we made the
   7227 (svc:output ) method fall back to properties if no output was present".
   7228 To do this, we'd have to
   7229 
   7230 (1) arrange for /nix/store/eeee-service/.properties to exist
   7231 
   7232  - add properties attribute to service functions
   7233  - write them to .properties in liminix-tools/services/builder.sh
   7234  - make sure they get passed through whne provided to all the service
   7235     builder functions
   7236 
   7237 [done] (2) pass the store directory to svc.open instead of  ..../.outputs
   7238 
   7239 (3) make service:output look in both places
   7240 
   7241 (4) write the damn firewall rule
   7242 
   7243 Mon Mar 17 21:13:36 GMT 2025
   7244 
   7245 Argh why is it never simple?
   7246 
   7247 We need to write a rate-limiting firewall rule for each interface to
   7248 restrict icmp on that interface. This is not easy to reconcile with
   7249 putting them in default-rules because how do we generate multiple
   7250 array elements by config file templating?
   7251 
   7252 There are two things in my mind now:
   7253 
   7254 1) could we have some better way of manipulating the firewall rules
   7255 such that the rules from different modules are composable
   7256 
   7257 this is complicated somewhat by ordering: if every rule in a chain is
   7258 "drop" or "accept" then it's easy to add another, but if the same
   7259 chain does first one then the other, doing the other and then the one
   7260 will not work
   7261 
   7262 today we do e.g.
   7263 
   7264 input-ip6
   7265 -> reject-bogons
   7266 -> accept non-bogus-icmp
   7267 -> process per-zone allowlist
   7268 -> allow established,related on wan
   7269 -> allow all on lan (so why did we need an allowlist?)
   7270 
   7271 could we express this in a less sequential form? the
   7272 specification of what's allowed
   7273 
   7274 
   7275 input-ip6 for wan: is input-ip6 with the wan allowlist
   7276 input-ip6 for lan: is input-ip6 with the lan allowlist
   7277 
   7278 
   7279 input-ip6 for ppp0: is input-ip6 with the wan allowlist with a rate
   7280 limit for icmp
   7281 
   7282 ssh module wishes to modify the allowlist for lan/wan/both so that
   7283 it includes port 22
   7284 
   7285 am wondering if we could do default deny and _all_ the rules
   7286 (except for bogons) are allows
   7287 
   7288 maybe we have the concept of "subtraction": a rule can be an allow
   7289 preceded by some number of drops which (at least by convention; this is
   7290 probably hard to enforce) are "carve outs" of the packets that are
   7291 being allowed.
   7292 
   7293 ... it's hard to express the forward-ipv6 in these terms, though.
   7294 we end up with "some drops and then multiple accepts"
   7295 
   7296 we have
   7297 (and (not (or drop1 drop2 ...)) (or accept1 accept2 ...))
   7298 
   7299 and to add ssh we need to break into the second clause instead of
   7300 composing at the top level
   7301 
   7302 (and (not (or drop1 drop2 ...))
   7303      (or accept1 accept2 accept-ssh...))
   7304 
   7305 
   7306 then the icmp bogons composite rule is "drop weird icmp and then
   7307 allow what's left"
   7308 
   7309 (side note: maybe we could use a map to do interface name -> bandwidth
   7310 for rate limiting)
   7311 
   7312 
   7313 
   7314 
   7315 a composite rule might be a bunch of denies and then an allow
   7316 for anything the
   7317 
   7318 2) some kinda syntax for referencing outputs (or properties) that's not
   7319 just string interpolation
   7320 
   7321 
   7322 ----
   7323 
   7324 I think we could address the immediate problem by writing a rule for
   7325 rate-limiting that looks up the rate in a map, and some maps (with
   7326 extraText) that get the rates from service properties? And that would
   7327 suffice for addressing the RoS audit, at least
   7328 
   7329 Tue Mar 18 18:48:22 GMT 2025
   7330 
   7331 Unless the interface exists, we do not (at least, may not) know its
   7332 name because that's an output. So the fact that it has a permanent
   7333 property is not per se terribly useful
   7334 
   7335 limit rate 50000 bytes / minute accept
   7336 
   7337 
   7338 nft add rule ip nat postrouting snat to ip saddr map { 192.168.1.0/24 : 10.0.0.1, 192.168.2.0/24 : 10.0.0.2 }
   7339 
   7340 nft add rule table-ip input-ip4 ip daddr 2.2.2.3/32 limit rate iifname map { "eth0": 10, "ppp0": 20 } kbytes/second   accept
   7341 
   7342 nft add map 'table-ip intf-limits  { typeof 5000000 ;  elements = { lan: 50000000, ppp0: 3500000 } ; }'
   7343 
   7344 OK, we can't do rate lookup in a map because the nftables grammar only
   7345 supports a numeric literal for limit_rate_bytes. so we're back to writing
   7346 a collection of rules, one for each interface with an ifname output,
   7347 that sets the limit for that interface
   7348 
   7349 * we could do this all in one element of a rules list, with newlines
   7350 between each actual rule
   7351 
   7352 * we could add extraText to the ruleset syntax - but does it go at the
   7353 start of the rules or the end or somewhere in the middle? this is
   7354 almost worse
   7355 
   7356 * we could pick up where we left off on march 17 and redesign the
   7357   firewall module
   7358 
   7359 gonna be option 1 isn't it?
   7360 
   7361 Tue Mar 25 00:13:31 GMT 2025
   7362 
   7363 the logic for watch-outputs is not correct
   7364 
   7365 (1) when we first read outputs, how do we know if the controlled
   7366 service is up to date wrt those outputs? we should perform the action
   7367 for the first time after reading initial state and before waiting
   7368 
   7369 (2) it isn't writing the new outputs back into trees, so will refresh
   7370 continually after the fisrt change
   7371 
   7372 set tree to empty for each service
   7373 loop:
   7374 for each service
   7375   read new tree
   7376   if different
   7377     do action
   7378     set tree = new tree
   7379 wait for changes
   7380 next iteration
   7381 
   7382 Fri Mar 28 23:25:49 GMT 2025
   7383 
   7384 the ppp connection doesn't come back after a&a reset the lns, this has
   7385 happened twice now. Possibly-relevant log entries:
   7386 
   7387 
   7388 2025-03-27 01:10:20.189135502 rotuer dhcp6c.prefix.dhcp6c.wan.link.pppoe.int.link.a.192.168.8.1 Executed "ip address change 2001:8b0:de3a:40de::1/64 dev int valid_lft 5682 preferred_lft 5682", exit code true
   7389 2025-03-27 01:10:20.189182063 rotuer dhcp6c.addr.dhcp6c.wan.link.pppoe.wan.link.pppoe Executed "ip address change 2001:8b0:1111:1111:0:ffff:d9a9:14de/128 dev ppp0 valid_lft 5682 preferred_lft 2082", exit code true
   7390 
   7391 # am assuming these are just normal updates from remote dhcp6
   7392 
   7393 2025-03-27 01:11:19.179528428 rotuer wan.link.pppoe rcvd [LCP TermReq id=0x0]
   7394 2025-03-27 01:11:19.179542189 rotuer wan.link.pppoe LCP terminated by peer
   7395 2025-03-27 01:11:19.179545869 rotuer wan.link.pppoe Connect time 54273.0 minutes.
   7396 2025-03-27 01:11:19.179550109 rotuer wan.link.pppoe Sent 3022278191 bytes, received 2202783935 bytes.
   7397 2025-03-27 01:11:19.183056872 rotuer wan.link.pppoe sent [LCP TermAck id=0x0]
   7398 # ppp died
   7399 2025-03-27 01:11:19.183071352 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: carrier => 0 event on
   7400 2025-03-27 01:11:19.183076072 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Failed to send RS (Network unreachable)
   7401 2025-03-27 01:11:19.183081592 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Starting RELEASE transaction (timeout 4294967295s, max rc 5)
   7402 2025-03-27 01:11:19.183086312 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Send RELEASE message (elapsed 0ms, rc 0)
   7403 2025-03-27 01:11:19.183091992 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Failed to send RELEASE message to ff02::1:2 (Network unreachable)
   7404 2025-03-27 01:11:19.183096392 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: (re)starting transaction on ppp0
   7405 
   7406 # dhcp6c noticed no ppp so tried to release address. it can't because
   7407 #  ppp is down. how did it know it was time to say byebye?
   7408 
   7409 2025-03-27 01:11:19.198178337 rotuer int.link.a.192.168.8.1.dnsmasq dnsmasq-dhcp[631]: router advertisement on 2001:8b0:de3a:40de::, old prefix for int
   7410 2025-03-27 01:11:19.199068668 rotuer dhcp6c.prefix.dhcp6c.wan.link.pppoe.int.link.a.192.168.8.1 Executed "ip address del 2001:8b0:de3a:40de::1/64 dev int", exit code true
   7411 # our prefix delegation is no longer ours
   7412 
   7413 2025-03-27 01:11:19.199381632 rotuer dhcp6c.addr.dhcp6c.wan.link.pppoe.wan.link.pppoe ip: RTNETLINK answers: Address not available
   7414 2025-03-27 01:11:19.199401552 rotuer dhcp6c.addr.dhcp6c.wan.link.pppoe.wan.link.pppoe /nix/store/anz85qjb2qw084f5xhpx4qndp260xr9i-lua-tty-aarch64-unknown-linux-musl/bin/lua: ...ch64-unknown-linux-musl-0.1/share/lua/5.3/anoia/init.lua:93: Error executing "ip address del 2001:8b0:1111:1111:0:ffff:d9a9:14de/128 dev ppp0" (exit)
   7415 
   7416 this is the ip6 address that ppp negotiated.  is this command failing because
   7417 it was removed already?
   7418 
   7419 [....]
   7420 2025-03-27 01:11:25.545493523 rotuer wan.link.pppoe Script /nix/store/9n2314z07z1g9dd3sqr0kndinjv0vma3-ip6-up started (pid 10346)
   7421 2025-03-27 01:11:25.551376155 rotuer wan.link.pppoe Script /nix/store/9n2314z07z1g9dd3sqr0kndinjv0vma3-ip6-up finished (pid 10346), status = 0x0
   7422 2025-03-27 01:11:25.552949055 rotuer wan.link.pppoe sh: write error: Broken pipe
   7423 2025-03-27 01:11:25.553494501 rotuer wan.link.pppoe Script /nix/store/jkvnjhiqjahydmns33z5lni1hf9sl3x8-ip-up finished (pid 10345), status = 0x1
   7424 2025-03-27 01:11:26.596566491 rotuer wlan0.link.hostapd wlan0: STA-OPMODE-SMPS-MODE-CHANGED 96:75:33:6c:6b:86 static
   7425 2025-03-27 01:11:26.656620107 rotuer wlan0.link.hostapd wlan0: STA-OPMODE-SMPS-MODE-CHANGED 96:75:33:6c:6b:86 off
   7426 2025-03-27 01:11:27.189590642 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Failed to send RS (Network unreachable)
   7427 
   7428 it's supposed to send only one notification (each up-script only sends
   7429 if an output the other has created is there).
   7430 
   7431 ~~maybe we're not wiping the outputs when it terminates?~~ checked, we are.
   7432 
   7433 
   7434 2025-03-27 01:11:27.279458704 rotuer int.link.a.192.168.8.1.dnsmasq dnsmasq-dhcp[631]: no address range available for DHCPv6 request via int
   7435 2025-03-27 01:11:27.557594914 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Failed to send SOLICIT message to ff02::1:2 (Network unreachable)
   7436 2025-03-27 01:11:31.193583256 rotuer dhcp6c.wan.link.pppoe odhcp6c[615]: Failed to send RS (Network unreachable)
   7437 
   7438 Hypothesis
   7439 
   7440 1) when the remote end bounces ppp, s6 restarts the ppp process
   7441 but this doesn't cause dependent services to notice, so odhcpc,
   7442 which is bound to the interface, doesn't see that we now have a
   7443 new interface but with the same name as the old one
   7444 
   7445 and/or
   7446 
   7447 2) there is a race between acquire-*.fnl starting and the
   7448 prefix/address outputs being updated so that we miss the first
   7449 value change.
   7450 
   7451 Tue Apr  1 21:29:03 BST 2025
   7452 
   7453 what to do with the web site?
   7454 
   7455 * we could add the "community" and "development" pages to the manual,
   7456 but we probably don't want the blog entries to be in the liminix git
   7457 repo because workflow
   7458 
   7459 * if we do that, the ->html conversion in the manual needs to have
   7460   better nav
   7461 
   7462 links we want on the homepage
   7463 
   7464 "I am new to Liminix and want to find if it's for me"
   7465  - introduction/tutorial (how do i use it)
   7466  - hardware list (is my device supported)
   7467    - which includes how to install the system
   7468 
   7469 "I am ready to run, and need a reference for stuff"
   7470 [this is a merge of the existing config and admin sections]
   7471  - what is a module, what is a service
   7472  - how to do secrets
   7473  - list of service and module options
   7474  - using a running system: services and logs
   7475    (move controlled services stuff up a level, its not runtime)
   7476  - updating/changing the configuration
   7477    writable fs: use outputs.updater
   7478    readonly fs: use levitate
   7479 
   7480 "I want to stay in touch/find out what's new"
   7481  - blog
   7482  - mailing lists
   7483  - irc
   7484  - CoC
   7485 
   7486 "I want to contribute"
   7487 Developer manual, plus
   7488  - mailing lists
   7489  - git repo
   7490    - how to send patches
   7491  - also transplant "module implementation" here
   7492  - porting
   7493    - how to bring up
   7494    - what we look for in a new device patch (kconfig style
   7495 
   7496 
   7497 perhaps we can get rid of generic "installation" in the manual
   7498 and have each method transcluded into the hardware device descriptions
   7499 
   7500 
   7501 
   7502 see also:
   7503 1) "Continuous updates" is misleading as it gives the impression
   7504 downstreams would be restarted if an upstream restarts. Not true.
   7505 We should describe secrets subscriber here
   7506 
   7507 
   7508 -----
   7509 
   7510 leaving us with these titles remaining
   7511 
   7512 * tutorial
   7513 * hardware
   7514 * reference (could just call it "manual")
   7515 * development
   7516 * blog
   7517 
   7518 and these which get moved
   7519 
   7520 * configuration/admin -> tutorial
   7521 * Module options -> sublevel in Reference
   7522 * outputs -> transcluded in hardware
   7523   (might also add as an appendix, so that porters can see all in one place)
   7524 
   7525 maybe also footer link for
   7526 - CoC
   7527 - privacy policy
   7528 - ?
   7529 
   7530 source for all of these except blog and landing page is the doc/ folder
   7531 
   7532 landing page will have some big rectangles that essentially duplicate
   7533 the menu items
   7534 
   7535 ----
   7536 
   7537 to get there from here:
   7538 
   7539 1) we need to know the heading titles for a ToC to use as drop-down
   7540 menus in the template, so will have to pass twice over the documents.
   7541 Note that the same template is used for each doc so we can't expect the
   7542 titles of the other docs to be provided by pandoc as variables
   7543 
   7544 (but maybe we could pass them in on the command line so as not to
   7545 rewrite template.json?)
   7546 
   7547 note that we also need to use the template with the blog files,
   7548 although for those we also need title and date frontmatter
   7549 
   7550 if the blog sources the template at build time to make pages, it's
   7551 always going to be out of sync with the manual.
   7552 
   7553 would javascript be acceptable?
   7554 
   7555 should we just monorepo the two things together? we could run jekyll as
   7556 part of the doc target, or even pandoc the markdown directly
   7557 
   7558 apparently myhtic.telent.net is running an rsync server?
   7559 
   7560 1) it needs doc/ removing from its path
   7561    path = "/var/www/blogs/www.liminix.org/_site/doc";
   7562    in hosts/myhtic.nix
   7563    (and moving to rmeote)
   7564 
   7565 2) make install should add doc to the path, for the manual,
   7566   and not for the blog entries which should be in yyyy/mm/dd folders
   7567 
   7568 Sun Apr  6 17:48:33 BST 2025
   7569 
   7570 This is all getting quite involved and I'm not convinced it's the
   7571 simplest way forward
   7572 
   7573 - convert the manual to asciidoctor and make it have a sidebar
   7574   - use --embedded flag to splice in header/footer
   7575 
   7576 - the landing page can have big display-sized links to different
   7577 manual sections and to the blog
   7578 
   7579 - get rid of the blog content that's not actually posts, merge it into
   7580   the manual
   7581 
   7582 - the blog also needs the header/footer spliced in
   7583 
   7584 site nav has three options: "home", "news", "manual"
   7585 - unless we want to put the manual deeplinks from the homepage in
   7586  there as well
   7587 - if we do that, need to indicate somehow that they're part of the
   7588  manual, not distinct from it
   7589 
   7590 do we need to move urls around? maybe not so much
   7591 
   7592 what to do about the "hardware" page?
   7593 
   7594  - do we really expect the reader to scroll through every device
   7595  that's not theirs?
   7596  - there's going to be a lot of repeated text for similar devices
   7597  - "generic" instructions might go in the body of the manual with
   7598    devices as an appendix. However, you have to read the relevant
   7599    appendix section to make sense of the generic instructions anyway.
   7600    If only we had hypertext
   7601 
   7602 
   7603 Mon Apr  7 23:49:40 BST 2025
   7604 
   7605 DOC TODO
   7606 
   7607 [done] * need to explain the mailing lists and IRC somewhere
   7608 
   7609 [done] * markup the devices section as an appendix.
   7610 
   7611 [done] * docs for outputs? maybe appendix ii
   7612 
   7613 [done] * move "module implementation" from admin to dev (maybe?)
   7614 
   7615 [done] * CI: move from website to Development
   7616 
   7617 [done] * move info on the Community page to Introduction
   7618 
   7619 [halfarsed done] * write doc for porting to new hw
   7620  - how to bring up
   7621  - what we look for in a new device patch (kconfig style etc)
   7622 
   7623 [done] * add rsyncy thing to rmeote
   7624 
   7625 * we still have serial connection guff in both installation and
   7626   development sections
   7627 
   7628 * convert all the embedded rst to adoc
   7629 
   7630 * remove pages that are not posts from jekyll blog
   7631 
   7632 * landing page
   7633 
   7634 * "Continuous updates" is misleading as it gives the impression
   7635 downstreams would be restarted if an upstream restarts. Not true.
   7636 We should describe secrets subscriber here
   7637 
   7638 * some basic css to make it not the same as (I assume) every single
   7639   other asciidoc site