From cb95bb6df81dff3fc3db4f5fa7f7a7f0b5a0fdf1 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 21 Jun 2020 09:43:13 +0200 Subject: [PATCH] move README into (hugo-powered) website router7.org --- README.md | 161 +------------- docs/CNAME | 1 + docs/architecture/index.html | 200 ++++++++++++++++++ docs/index.html | 94 ++++++++ docs/installation/index.html | 146 +++++++++++++ docs/robots.txt | 2 + docs/sass/sidebar.css | 19 ++ docs/sitemap.xml | 17 ++ website/archetypes/default.md | 6 + website/config.toml | 19 ++ website/content/_index.md | 37 ++++ website/content/architecture.md | 58 +++++ website/content/installation.md | 93 ++++++++ website/layouts/robots.txt | 2 + ...s_f300667da4f5b5f84e1a9e0702b2fdde.content | 19 ++ ...scss_f300667da4f5b5f84e1a9e0702b2fdde.json | 1 + website/static/CNAME | 1 + website/themes/router7/LICENSE | 20 ++ website/themes/router7/archetypes/default.md | 2 + .../themes/router7/assets/sass/sidebar.scss | 23 ++ website/themes/router7/layouts/404.html | 0 .../router7/layouts/_default/baseof.html | 17 ++ .../themes/router7/layouts/_default/list.html | 31 +++ .../router7/layouts/_default/single.html | 20 ++ website/themes/router7/layouts/index.html | 17 ++ .../router7/layouts/partials/footer.html | 7 + .../themes/router7/layouts/partials/head.html | 14 ++ .../router7/layouts/partials/header.html | 0 .../themes/router7/layouts/partials/nav.html | 15 ++ website/themes/router7/theme.toml | 21 ++ 30 files changed, 903 insertions(+), 160 deletions(-) create mode 100644 docs/CNAME create mode 100644 docs/architecture/index.html create mode 100644 docs/index.html create mode 100644 docs/installation/index.html create mode 100644 docs/robots.txt create mode 100644 docs/sass/sidebar.css create mode 100644 docs/sitemap.xml create mode 100644 website/archetypes/default.md create mode 100644 website/config.toml create mode 100644 website/content/_index.md create mode 100644 website/content/architecture.md create mode 100644 website/content/installation.md create mode 100644 website/layouts/robots.txt create mode 100644 website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.content create mode 100644 website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.json create mode 100644 website/static/CNAME create mode 100644 website/themes/router7/LICENSE create mode 100644 website/themes/router7/archetypes/default.md create mode 100644 website/themes/router7/assets/sass/sidebar.scss create mode 100644 website/themes/router7/layouts/404.html create mode 100644 website/themes/router7/layouts/_default/baseof.html create mode 100644 website/themes/router7/layouts/_default/list.html create mode 100644 website/themes/router7/layouts/_default/single.html create mode 100644 website/themes/router7/layouts/index.html create mode 100644 website/themes/router7/layouts/partials/footer.html create mode 100644 website/themes/router7/layouts/partials/head.html create mode 100644 website/themes/router7/layouts/partials/header.html create mode 100644 website/themes/router7/layouts/partials/nav.html create mode 100644 website/themes/router7/theme.toml diff --git a/README.md b/README.md index 0fa1387..889dcb8 100644 --- a/README.md +++ b/README.md @@ -8,163 +8,4 @@ router7 is a pure-Go implementation of a small home internet router. It comes wi Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see [CONTRIBUTING.md](CONTRIBUTING.md) for details about which contributions are welcome. -## Motivation - -Before starting router7, I was using the [Turris Omnia](https://omnia.turris.cz/en/) router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of [odhcp6c](https://git.openwrt.org/?p=project/odhcp6c.git;a=shortlog), OpenWrt’s DHCPv6 client. That version is incompatible with fiber7’s DHCP server setup (I think there are shortcomings on both sides). - -It was not only quicker to develop my own router than to wait for either side to resolve the issue, but it was also a lot of fun and allowed me to really tailor my router to my needs, experimenting with a bunch of interesting ideas I had. - -## Project goals - -* Maximize internet connectivity: retain the most recent DHCP configuration across reboots and even after its expiration (chances are the DHCP server will be back before the configuration stops working). -* Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity. -* Safe and quick updates - * Auto-rollback of updates which result in loss of connectivity: the diagnostics daemon assesses connectivity state, the update tool reads it and rolls back faulty updates. - * Thanks to kexec, updates translate into merely 13s of internet connectivity loss. -* Easy debugging - * Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into [Wireshark](https://www.wireshark.org/), allowing for live and retro-active debugging. - * The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you. - * All state in the system is stored as human-readable JSON within the `/perm` partition and can be modified. - -## Hardware - -The reference hardware platform is the [PC Engines™ apu2c4](https://pcengines.ch/apu2c4.htm) system board. It features a 1 GHz quad core amd64 CPU, 4 GB of RAM, 3 Ethernet ports and a DB9 serial port. It conveniently supports PXE boot, the schematics and bootloader sources are available. I recommend the [msata16g](https://pcengines.ch/msata16g.htm) SSD module for reliable persistent storage and the [usbcom1a](https://pcengines.ch/usbcom1a.htm) serial adapter if you don’t have one already. - -Other hardware might work, too, but is not tested. - -### Teensy rebootor - -The cheap and widely-available [Teensy++ USB development board](https://www.pjrc.com/store/teensypp.html) comes with a firmware called rebootor, which is used by the [`teensy_loader_cli`](https://www.pjrc.com/teensy/loader_cli.html) program to perform hard resets. - -This setup can be used to programmatically reset the apu2c4 (from `rtr7-recover`) by connecting the Teensy++ to the [apu2c4’s reset pins](http://pcengines.ch/pdf/apu2.pdf): -* connect the Teensy++’s `GND` pin to the apu2c4 J2’s pin 4 (`GND`) -* connect the Teensy++’s `B7` pin to the apu2c4 J2’s pin 5 (`3.3V`, resets when pulled to `GND`) - -You can find a working rebootor firmware .hex file at https://github.com/PaulStoffregen/teensy_loader_cli/issues/38 - -## Architecture - -router7 is based on [gokrazy](https://gokrazy.org/): it is an appliance which gets packed into a hard disk image, containing a FAT partition with the kernel, a read-only SquashFS partition for the root file system and an ext4 partition for permanent data. - -The individual services can be found in [github.com/rtr7/router7/cmd](https://godoc.org/github.com/rtr7/router7/cmd). - -* Each service runs in a separate process. -* Services communicate with each other by persisting state files. E.g., `cmd/dhcp4` writes `/perm/dhcp4/wire/lease.json`. -* A service notifies other services about state changes by sending them signal `SIGUSR1`. - -### Configuration files - -| File | Consumer(s) | Purpose | -|---|---|---| -| `/perm/interfaces.json` | `netconfigd` | Set IP/MAC addresses of `uplink0` and `lan0` | -| `/perm/portforwardings.json` | `netconfigd` | Configure nftables port forwarding rules | -| `/perm/dhcp6/duid` | `dhcp6` | Set DHCP Unique Identifier (DUID) for obtaining static leases | - -### State files - -| File | Producer | Consumer(s) | Purpose | -|---|---|---|---| -| `/perm/dhcp4/wire/ack` | `dhcp4` | `dhcp4` | last DHCPACK packet for renewals across restarts | -| `/perm/dhcp4/wire/lease.json` | `dhcp4` | `netconfigd` | Obtained DHCPv4 lease | -| `/perm/dhcp6/wire/lease.json` | `dhcp6` | `netconfigd`, `radvd` | Obtained DHCPv6 lease | -| `/perm/dhcp4d/leases.json` | `dhcp4d` | `dhcp4d`, `dnsd` | DHCPv4 leases handed out (including hostnames) | - -### Available ports - -| Port | Purpose | -|---|---| -| `:8053` | `dnsd` metrics (forwarded requests) -| `:8066` | `netconfigd` metrics (nftables counters) -| `:80` | gokrazy web interface -| `:67` | `dhcp4d` -| `:58` | `radvd` -| `:53` | `dnsd` -| `:8077` | `backupd` (serve backup.tar.gz) -| `:7733` | `diagd` (perform diagnostics) -| `:5022` | `captured` (serve captured packets) - -Here’s an example of the diagd output: - -diagd output - -Here’s an example of the metrics when scraped with [Prometheus](https://prometheus.io/) and displayed in [Grafana](https://grafana.com/): - -metrics in grafana - -## Installation - -Connect your serial adapter ([usbcom1a](https://pcengines.ch/usbcom1a.htm) works well if you don’t have one already) to the apu2c4 and start a program to use it, e.g. `screen /dev/ttyUSB0 115200`. Then, power on the apu2c4 and configure it to do PXE boot: - -* Press `F10` to enter the boot menu -* Press `3` to enter setup -* Press `n` to enable network boot -* Press `c` to move mSATA to the top of the boot order -* Press `e` to move iPXE to the top of the boot order -* Press `s` to save configuration and exit - -Connect a network cable on `net0`, the port closest to the serial console port: - -router7 development setup - -Next, build a router7 image: - -``` -go get -u github.com/gokrazy/tools/cmd/gokr-packer github.com/rtr7/tools/cmd/... -go get -u -d github.com/rtr7/router7 -mkdir /tmp/recovery -GOARCH=amd64 gokr-packer \ - -hostname=router7 \ - -overwrite_boot=/tmp/recovery/boot.img \ - -overwrite_mbr=/tmp/recovery/mbr.img \ - -overwrite_root=/tmp/recovery/root.img \ - -kernel_package=github.com/rtr7/kernel \ - -firmware_package=github.com/rtr7/kernel \ - -gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp \ - -serial_console=ttyS0,115200n8 \ - github.com/rtr7/router7/cmd/... -``` - -Run `rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img` to: - -* trigger a reset if a Teensy with the rebootor firmware is attached -* serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4) -* serve via TFTP: - * the PXELINUX bootloader - * the router7 kernel - * an initrd archive containing the rtr7-recovery-init program and mke2fs -* serve via HTTP the boot and root images -* optionally serve via HTTP a backup.tar.gz image containing files for /perm (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure) -* exit once the router successfully wrote the images to disk - -### Updates - -Run e.g. `rtr7-safe-update -updates_dir=$HOME/router7/updates` to: - -* verify the router currently has connectivity, abort the update otherwise -* download a backup archive of `/perm` -* build a new image -* update the router -* wait until the router restored connectivity, roll back the update using `rtr7-recover` otherwise - -The update step uses kexec to reduce the downtime to approximately 15 seconds. - -### Manual Recovery - -Given `rtr7-safe-update`’s safeguards, manual recovery should rarely be required. - -To manually roll back to an older image, invoke `rtr7-safe-update` via the -`recover.bash` script in the image directory underneath `-updates_dir`, e.g.: - -``` -% cd ~/router7/updates/2018-07-03T17:33:52+02:00 -% ./recover.bash -``` - -### Prometheus - -See https://github.com/rtr7/router7/tree/master/contrib/prometheus for example -configuration files, and install the [router7 Grafana -Dashboard](https://grafana.com/dashboards/8288). +**For more details, please see [router7.org](https://router7.org/)** diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..b92bc8f --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +router7.org diff --git a/docs/architecture/index.html b/docs/architecture/index.html new file mode 100644 index 0000000..36b9e53 --- /dev/null +++ b/docs/architecture/index.html @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + router7: architecture + + +
+
+
+
+

Architecture

+

router7 is based on gokrazy: it is an appliance which gets packed into a hard disk image, containing a FAT partition with the kernel, a read-only SquashFS partition for the root file system and an ext4 partition for permanent data.

+

The individual services can be found in github.com/rtr7/router7/cmd

+
    +
  • Each service runs in a separate process.
  • +
  • Services communicate with each other by persisting state files. E.g., cmd/dhcp4 writes /perm/dhcp4/wire/lease.json.
  • +
  • A service notifies other services about state changes by sending them signal SIGUSR1.
  • +
+

Configuration files

+ + + + + + + + + + + + + + + + + + + + + + + + + +
FileConsumer(s)Purpose
/perm/interfaces.jsonnetconfigdSet IP/MAC addresses of uplink0 and lan0
/perm/portforwardings.jsonnetconfigdConfigure nftables port forwarding rules
/perm/dhcp6/duiddhcp6Set DHCP Unique Identifier (DUID) for obtaining static leases
+

State files

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FileProducerConsumer(s)Purpose
/perm/dhcp4/wire/ackdhcp4dhcp4last DHCPACK packet for renewals across restarts
/perm/dhcp4/wire/lease.jsondhcp4netconfigdObtained DHCPv4 lease
/perm/dhcp6/wire/lease.jsondhcp6netconfigd, radvdObtained DHCPv6 lease
/perm/dhcp4d/leases.jsondhcp4ddhcp4d, dnsdDHCPv4 leases handed out (including hostnames)
+

Available ports

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PortPurpose
<public>:8053dnsd metrics (forwarded requests)
<public>:8066netconfigd metrics (nftables counters)
<private>:80gokrazy web interface
<private>:67dhcp4d
<private>:58radvd
<private>:53dnsd
<private>:8077backupd (serve backup.tar.gz)
<private>:7733diagd (perform diagnostics)
<private>:5022captured (serve captured packets)
+

Here’s an example of cmd/diagd output:

+

diagd output

+

Here’s an example of cmd/netconfigd metrics when scraped with Prometheus and displayed in Grafana:

+

metrics in grafana

+ + +
+ +

+ © 2018 Michael Stapelberg and contributors +

+
+ +
+ + +
+
+ + + + + + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..095b91b --- /dev/null +++ b/docs/index.html @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + router7: a small home internet router completely written in Go + + +
+
+
+
+

router7

+

router7 is a pure-Go implementation of a small home internet router. It comes with all the services required to make a fiber7 internet connection work (DHCPv4, DHCPv6, DNS, etc.).

+

Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see CONTRIBUTING.md for details about which contributions are welcome.

+

Motivation

+

Before starting router7, I was using the Turris Omnia router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of odhcp6c, OpenWrt’s DHCPv6 client. That version is incompatible with fiber7’s DHCP server setup (I think there are shortcomings on both sides).

+

It was not only quicker to develop my own router than to wait for either side to resolve the issue, but it was also a lot of fun and allowed me to really tailor my router to my needs, experimenting with a bunch of interesting ideas I had.

+

Project goals

+
    +
  • Maximize internet connectivity: retain the most recent DHCP configuration across reboots and even after its expiration (chances are the DHCP server will be back before the configuration stops working).
  • +
  • Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity.
  • +
  • Safe and quick updates +
      +
    • Auto-rollback of updates which result in loss of connectivity: the diagnostics daemon assesses connectivity state, the update tool reads it and rolls back faulty updates.
    • +
    • Thanks to kexec, updates translate into merely 13s of internet connectivity loss.
    • +
    +
  • +
  • Easy debugging +
      +
    • Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into Wireshark, allowing for live and retro-active debugging.
    • +
    • The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you.
    • +
    • All state in the system is stored as human-readable JSON within the /perm partition and can be modified.
    • +
    +
  • +
+

Hardware

+

The reference hardware platform is the PC Engines™ apu2c4 system board. It features a 1 GHz quad core amd64 CPU, 4 GB of RAM, 3 Ethernet ports and a DB9 serial port. It conveniently supports PXE boot, the schematics and bootloader sources are available. I recommend the msata16g SSD module for reliable persistent storage and the usbcom1a serial adapter if you don’t have one already.

+

Other hardware might work, too, but is not tested.

+ + +
+ +

+ © 2018 Michael Stapelberg and contributors +

+
+
+
+
+ + +
+
+ + + + + + + + diff --git a/docs/installation/index.html b/docs/installation/index.html new file mode 100644 index 0000000..d88833d --- /dev/null +++ b/docs/installation/index.html @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + router7: installation + + +
+
+
+
+

Installation

+

Connect your serial adapter (usbcom1a works well if you don’t have one already) to the apu2c4 and start a program to use it, e.g. screen /dev/ttyUSB0 115200. Then, power on the apu2c4 and configure it to do PXE boot:

+
    +
  • Press F10 to enter the boot menu
  • +
  • Press 3 to enter setup
  • +
  • Press n to enable network boot
  • +
  • Press c to move mSATA to the top of the boot order
  • +
  • Press e to move iPXE to the top of the boot order
  • +
  • Press s to save configuration and exit
  • +
+

Connect a network cable on net0, the port closest to the serial console port:

+

router7 development setup

+

Next, build a router7 image:

+
go get -u github.com/gokrazy/tools/cmd/gokr-packer github.com/rtr7/tools/cmd/...
+go get -u -d github.com/rtr7/router7
+mkdir /tmp/recovery
+GOARCH=amd64 gokr-packer \
+	-hostname=router7 \
+	-overwrite_boot=/tmp/recovery/boot.img \
+	-overwrite_mbr=/tmp/recovery/mbr.img \
+	-overwrite_root=/tmp/recovery/root.img \
+	-kernel_package=github.com/rtr7/kernel \
+	-firmware_package=github.com/rtr7/kernel \
+	-gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp \
+	-serial_console=ttyS0,115200n8 \
+	github.com/rtr7/router7/cmd/...
+

Run rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img to:

+
    +
  • trigger a reset if a Teensy with the rebootor firmware is attached
  • +
  • serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4)
  • +
  • serve via TFTP: +
      +
    • the PXELINUX bootloader
    • +
    • the router7 kernel
    • +
    • an initrd archive containing the rtr7-recovery-init program and mke2fs
    • +
    +
  • +
  • serve via HTTP the boot and root images
  • +
  • optionally serve via HTTP a backup.tar.gz image containing files for /perm (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure)
  • +
  • exit once the router successfully wrote the images to disk
  • +
+

Updates

+

Run e.g. rtr7-safe-update -updates_dir=$HOME/router7/updates to:

+
    +
  • verify the router currently has connectivity, abort the update otherwise
  • +
  • download a backup archive of /perm
  • +
  • build a new image
  • +
  • update the router
  • +
  • wait until the router restored connectivity, roll back the update using rtr7-recover otherwise
  • +
+

The update step uses kexec to reduce the downtime to approximately 15 seconds.

+

Manual Recovery

+

Given rtr7-safe-update’s safeguards, manual recovery should rarely be required.

+

To manually roll back to an older image, invoke rtr7-safe-update via the +recover.bash script in the image directory underneath -updates_dir, e.g.:

+
% cd ~/router7/updates/2018-07-03T17:33:52+02:00
+% ./recover.bash
+

Teensy rebootor

+

The cheap and widely-available Teensy++ USB development board comes with a firmware called rebootor, which is used by the teensy_loader_cli program to perform hard resets.

+

This setup can be used to programmatically reset the apu2c4 (from rtr7-recover) by connecting the Teensy++ to the apu2c4’s reset pins:

+
    +
  • connect the Teensy++’s GND pin to the apu2c4 J2’s pin 4 (GND)
  • +
  • connect the Teensy++’s B7 pin to the apu2c4 J2’s pin 5 (3.3V, resets when pulled to GND)
  • +
+

You can find a working rebootor firmware .hex file at https://github.com/PaulStoffregen/teensy_loader_cli/issues/38

+

Prometheus

+

See https://github.com/rtr7/router7/tree/master/contrib/prometheus for example +configuration files, and install the router7 Grafana +Dashboard.

+ + +
+ +

+ © 2018 Michael Stapelberg and contributors +

+
+ +
+ + +
+
+ + + + + + + + diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 0000000..c076479 --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,2 @@ +User-Agent: * +sitemap: https://router7.org/sitemap.xml diff --git a/docs/sass/sidebar.css b/docs/sass/sidebar.css new file mode 100644 index 0000000..ab616f9 --- /dev/null +++ b/docs/sass/sidebar.css @@ -0,0 +1,19 @@ +.bd-toc { + position: sticky; + top: 4rem; + height: calc(100vh - 4rem); + overflow-y: auto; } + +.bd-toc ul { + list-style: none; + padding-left: 1em; + border-left: 1px solid #eee; } + +.bd-toc li { + margin-top: 1em; + margin-bottom: 1em; } + +/* TODO: move this to a separate style sheet */ +.bigbutton { + margin-left: 1em; + margin-right: 1em; } diff --git a/docs/sitemap.xml b/docs/sitemap.xml new file mode 100644 index 0000000..dd66b9a --- /dev/null +++ b/docs/sitemap.xml @@ -0,0 +1,17 @@ + + + + + https://router7.org/ + + + + https://router7.org/architecture/ + + + + https://router7.org/installation/ + + + \ No newline at end of file diff --git a/website/archetypes/default.md b/website/archetypes/default.md new file mode 100644 index 0000000..00e77bd --- /dev/null +++ b/website/archetypes/default.md @@ -0,0 +1,6 @@ +--- +title: "{{ replace .Name "-" " " | title }}" +date: {{ .Date }} +draft: true +--- + diff --git a/website/config.toml b/website/config.toml new file mode 100644 index 0000000..4ddfc68 --- /dev/null +++ b/website/config.toml @@ -0,0 +1,19 @@ +baseURL = "https://router7.org/" +languageCode = "en-us" +title = "router7" +theme = "router7" +disableKinds = ["RSS", "taxonomyTerm"] +publishDir = "../docs/" +enableRobotsTXT = true + +[markup.goldmark.renderer] +# Required for e.g. tags in markdown articles. +unsafe = true + +[menu] + + [[menu.main]] + name = "github" + title = "GitHub" + url = "https://github.com/rtr7/router7" + weight = 60 diff --git a/website/content/_index.md b/website/content/_index.md new file mode 100644 index 0000000..8b1a587 --- /dev/null +++ b/website/content/_index.md @@ -0,0 +1,37 @@ +--- +title: "router7: a small home internet router completely written in Go" +menu: + main: + title: "Home" + weight: 10 +--- + +# router7 + +router7 is a pure-Go implementation of a small home internet router. It comes with all the services required to make a [fiber7 internet connection](https://www.init7.net/en/internet/fiber7/) work (DHCPv4, DHCPv6, DNS, etc.). + +Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see [CONTRIBUTING.md](CONTRIBUTING.md) for details about which contributions are welcome. + +## Motivation + +Before starting router7, I was using the [Turris Omnia](https://omnia.turris.cz/en/) router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of [odhcp6c](https://git.openwrt.org/?p=project/odhcp6c.git;a=shortlog), OpenWrt’s DHCPv6 client. That version is incompatible with fiber7’s DHCP server setup (I think there are shortcomings on both sides). + +It was not only quicker to develop my own router than to wait for either side to resolve the issue, but it was also a lot of fun and allowed me to really tailor my router to my needs, experimenting with a bunch of interesting ideas I had. + +## Project goals + +* Maximize internet connectivity: retain the most recent DHCP configuration across reboots and even after its expiration (chances are the DHCP server will be back before the configuration stops working). +* Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity. +* Safe and quick updates + * Auto-rollback of updates which result in loss of connectivity: the diagnostics daemon assesses connectivity state, the update tool reads it and rolls back faulty updates. + * Thanks to kexec, updates translate into merely 13s of internet connectivity loss. +* Easy debugging + * Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into [Wireshark](https://www.wireshark.org/), allowing for live and retro-active debugging. + * The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you. + * All state in the system is stored as human-readable JSON within the `/perm` partition and can be modified. + +## Hardware + +The reference hardware platform is the [PC Engines™ apu2c4](https://pcengines.ch/apu2c4.htm) system board. It features a 1 GHz quad core amd64 CPU, 4 GB of RAM, 3 Ethernet ports and a DB9 serial port. It conveniently supports PXE boot, the schematics and bootloader sources are available. I recommend the [msata16g](https://pcengines.ch/msata16g.htm) SSD module for reliable persistent storage and the [usbcom1a](https://pcengines.ch/usbcom1a.htm) serial adapter if you don’t have one already. + +Other hardware might work, too, but is not tested. diff --git a/website/content/architecture.md b/website/content/architecture.md new file mode 100644 index 0000000..165c64f --- /dev/null +++ b/website/content/architecture.md @@ -0,0 +1,58 @@ +--- +title: "router7: architecture" +menu: + main: + title: "Architecture" + weight: 20 +--- + +# Architecture + +router7 is based on [gokrazy](https://gokrazy.org/): it is an appliance which gets packed into a hard disk image, containing a FAT partition with the kernel, a read-only SquashFS partition for the root file system and an ext4 partition for permanent data. + +The individual services can be found in [github.com/rtr7/router7/cmd](https://pkg.go.dev/github.com/rtr7/router7/cmd) + +* Each service runs in a separate process. +* Services communicate with each other by persisting state files. E.g., `cmd/dhcp4` writes `/perm/dhcp4/wire/lease.json`. +* A service notifies other services about state changes by sending them signal `SIGUSR1`. + +## Configuration files + +| File | Consumer(s) | Purpose | +|---|---|---| +| `/perm/interfaces.json` | `netconfigd` | Set IP/MAC addresses of `uplink0` and `lan0` | +| `/perm/portforwardings.json` | `netconfigd` | Configure nftables port forwarding rules | +| `/perm/dhcp6/duid` | `dhcp6` | Set DHCP Unique Identifier (DUID) for obtaining static leases | + +## State files + +| File | Producer | Consumer(s) | Purpose | +|---|---|---|---| +| `/perm/dhcp4/wire/ack` | `dhcp4` | `dhcp4` | last DHCPACK packet for renewals across restarts | +| `/perm/dhcp4/wire/lease.json` | `dhcp4` | `netconfigd` | Obtained DHCPv4 lease | +| `/perm/dhcp6/wire/lease.json` | `dhcp6` | `netconfigd`, `radvd` | Obtained DHCPv6 lease | +| `/perm/dhcp4d/leases.json` | `dhcp4d` | `dhcp4d`, `dnsd` | DHCPv4 leases handed out (including hostnames) | + +## Available ports + +| Port | Purpose | +|---|---| +| `:8053` | `dnsd` metrics (forwarded requests) +| `:8066` | `netconfigd` metrics (nftables counters) +| `:80` | gokrazy web interface +| `:67` | `dhcp4d` +| `:58` | `radvd` +| `:53` | `dnsd` +| `:8077` | `backupd` (serve backup.tar.gz) +| `:7733` | `diagd` (perform diagnostics) +| `:5022` | `captured` (serve captured packets) + +Here’s an example of `cmd/diagd` output: + +diagd output + +Here’s an example of `cmd/netconfigd` metrics when scraped with [Prometheus](https://prometheus.io/) and displayed in [Grafana](https://grafana.com/): + +metrics in grafana diff --git a/website/content/installation.md b/website/content/installation.md new file mode 100644 index 0000000..a6c0d74 --- /dev/null +++ b/website/content/installation.md @@ -0,0 +1,93 @@ +--- +title: "router7: installation" +menu: + main: + title: "Installation" + weight: 30 +--- + +# Installation + +Connect your serial adapter ([usbcom1a](https://pcengines.ch/usbcom1a.htm) works well if you don’t have one already) to the apu2c4 and start a program to use it, e.g. `screen /dev/ttyUSB0 115200`. Then, power on the apu2c4 and configure it to do PXE boot: + +* Press `F10` to enter the boot menu +* Press `3` to enter setup +* Press `n` to enable network boot +* Press `c` to move mSATA to the top of the boot order +* Press `e` to move iPXE to the top of the boot order +* Press `s` to save configuration and exit + +Connect a network cable on `net0`, the port closest to the serial console port: + +router7 development setup + +Next, build a router7 image: + +```shell +go get -u github.com/gokrazy/tools/cmd/gokr-packer github.com/rtr7/tools/cmd/... +go get -u -d github.com/rtr7/router7 +mkdir /tmp/recovery +GOARCH=amd64 gokr-packer \ + -hostname=router7 \ + -overwrite_boot=/tmp/recovery/boot.img \ + -overwrite_mbr=/tmp/recovery/mbr.img \ + -overwrite_root=/tmp/recovery/root.img \ + -kernel_package=github.com/rtr7/kernel \ + -firmware_package=github.com/rtr7/kernel \ + -gokrazy_pkgs=github.com/gokrazy/gokrazy/cmd/ntp \ + -serial_console=ttyS0,115200n8 \ + github.com/rtr7/router7/cmd/... +``` + +Run `rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img` to: + +* trigger a reset [if a Teensy with the rebootor firmware is attached](#rebootor) +* serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4) +* serve via TFTP: + * the PXELINUX bootloader + * the router7 kernel + * an initrd archive containing the rtr7-recovery-init program and mke2fs +* serve via HTTP the boot and root images +* optionally serve via HTTP a backup.tar.gz image containing files for `/perm` (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure) +* exit once the router successfully wrote the images to disk + +## Updates + +Run e.g. `rtr7-safe-update -updates_dir=$HOME/router7/updates` to: + +* verify the router currently has connectivity, abort the update otherwise +* download a backup archive of `/perm` +* build a new image +* update the router +* wait until the router restored connectivity, roll back the update using `rtr7-recover` otherwise + +The update step uses kexec to reduce the downtime to approximately 15 seconds. + +## Manual Recovery + +Given `rtr7-safe-update`’s safeguards, manual recovery should rarely be required. + +To manually roll back to an older image, invoke `rtr7-safe-update` via the +`recover.bash` script in the image directory underneath `-updates_dir`, e.g.: + +```shell +% cd ~/router7/updates/2018-07-03T17:33:52+02:00 +% ./recover.bash +``` + +## Teensy rebootor {#rebootor} + +The cheap and widely-available [Teensy++ USB development board](https://www.pjrc.com/store/teensypp.html) comes with a firmware called rebootor, which is used by the [`teensy_loader_cli`](https://www.pjrc.com/teensy/loader_cli.html) program to perform hard resets. + +This setup can be used to programmatically reset the apu2c4 (from `rtr7-recover`) by connecting the Teensy++ to the [apu2c4’s reset pins](http://pcengines.ch/pdf/apu2.pdf): +* connect the Teensy++’s `GND` pin to the apu2c4 J2’s pin 4 (`GND`) +* connect the Teensy++’s `B7` pin to the apu2c4 J2’s pin 5 (`3.3V`, resets when pulled to `GND`) + +You can find a working rebootor firmware .hex file at https://github.com/PaulStoffregen/teensy_loader_cli/issues/38 + +## Prometheus + +See https://github.com/rtr7/router7/tree/master/contrib/prometheus for example +configuration files, and install the [router7 Grafana +Dashboard](https://grafana.com/dashboards/8288). diff --git a/website/layouts/robots.txt b/website/layouts/robots.txt new file mode 100644 index 0000000..c076479 --- /dev/null +++ b/website/layouts/robots.txt @@ -0,0 +1,2 @@ +User-Agent: * +sitemap: https://router7.org/sitemap.xml diff --git a/website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.content b/website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.content new file mode 100644 index 0000000..ab616f9 --- /dev/null +++ b/website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.content @@ -0,0 +1,19 @@ +.bd-toc { + position: sticky; + top: 4rem; + height: calc(100vh - 4rem); + overflow-y: auto; } + +.bd-toc ul { + list-style: none; + padding-left: 1em; + border-left: 1px solid #eee; } + +.bd-toc li { + margin-top: 1em; + margin-bottom: 1em; } + +/* TODO: move this to a separate style sheet */ +.bigbutton { + margin-left: 1em; + margin-right: 1em; } diff --git a/website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.json b/website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.json new file mode 100644 index 0000000..d3d61f1 --- /dev/null +++ b/website/resources/_gen/assets/scss/sass/sidebar.scss_f300667da4f5b5f84e1a9e0702b2fdde.json @@ -0,0 +1 @@ +{"Target":"sass/sidebar.css","MediaType":"text/css","Data":{}} \ No newline at end of file diff --git a/website/static/CNAME b/website/static/CNAME new file mode 100644 index 0000000..b92bc8f --- /dev/null +++ b/website/static/CNAME @@ -0,0 +1 @@ +router7.org diff --git a/website/themes/router7/LICENSE b/website/themes/router7/LICENSE new file mode 100644 index 0000000..faff36e --- /dev/null +++ b/website/themes/router7/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2020 YOUR_NAME_HERE + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/website/themes/router7/archetypes/default.md b/website/themes/router7/archetypes/default.md new file mode 100644 index 0000000..ac36e06 --- /dev/null +++ b/website/themes/router7/archetypes/default.md @@ -0,0 +1,2 @@ ++++ ++++ diff --git a/website/themes/router7/assets/sass/sidebar.scss b/website/themes/router7/assets/sass/sidebar.scss new file mode 100644 index 0000000..d69786f --- /dev/null +++ b/website/themes/router7/assets/sass/sidebar.scss @@ -0,0 +1,23 @@ +.bd-toc { + position: sticky; + top: 4rem; + height: calc(100vh - 4rem); + overflow-y: auto +} + +.bd-toc ul { + list-style: none; + padding-left: 1em; + border-left: 1px solid #eee; +} + +.bd-toc li { + margin-top: 1em; + margin-bottom: 1em; +} + +/* TODO: move this to a separate style sheet */ +.bigbutton { + margin-left: 1em; + margin-right: 1em; +} diff --git a/website/themes/router7/layouts/404.html b/website/themes/router7/layouts/404.html new file mode 100644 index 0000000..e69de29 diff --git a/website/themes/router7/layouts/_default/baseof.html b/website/themes/router7/layouts/_default/baseof.html new file mode 100644 index 0000000..8933ecb --- /dev/null +++ b/website/themes/router7/layouts/_default/baseof.html @@ -0,0 +1,17 @@ + + + {{- partial "head.html" . -}} + +
+
+ + {{- partial "header.html" . -}} + +{{ block "main" . }} +{{ end }} + +
+
+ {{- partial "footer.html" . -}} + + diff --git a/website/themes/router7/layouts/_default/list.html b/website/themes/router7/layouts/_default/list.html new file mode 100644 index 0000000..6bfc04e --- /dev/null +++ b/website/themes/router7/layouts/_default/list.html @@ -0,0 +1,31 @@ +{{ define "main" }} +
+
+ + {{- partial "nav.html" . -}} +{{ .Content }} + +

list template

+ + + +
+ +

+ © 2018 Michael Stapelberg and contributors +

+
+
+ +
+
+{{ end }} + diff --git a/website/themes/router7/layouts/_default/single.html b/website/themes/router7/layouts/_default/single.html new file mode 100644 index 0000000..c9d8058 --- /dev/null +++ b/website/themes/router7/layouts/_default/single.html @@ -0,0 +1,20 @@ +{{ define "main" }} +
+
+ + {{- partial "nav.html" . -}} +{{ .Content }} + +
+ +

+ © 2018 Michael Stapelberg and contributors +

+
+
+ +
+
+{{ end }} diff --git a/website/themes/router7/layouts/index.html b/website/themes/router7/layouts/index.html new file mode 100644 index 0000000..e7942bf --- /dev/null +++ b/website/themes/router7/layouts/index.html @@ -0,0 +1,17 @@ +{{ define "main" }} +
+
+ + {{- partial "nav.html" . -}} +{{ .Content }} + +
+ +

+ © 2018 Michael Stapelberg and contributors +

+
+
+
+
+{{ end }} diff --git a/website/themes/router7/layouts/partials/footer.html b/website/themes/router7/layouts/partials/footer.html new file mode 100644 index 0000000..5e4c00f --- /dev/null +++ b/website/themes/router7/layouts/partials/footer.html @@ -0,0 +1,7 @@ + + + + + + + diff --git a/website/themes/router7/layouts/partials/head.html b/website/themes/router7/layouts/partials/head.html new file mode 100644 index 0000000..9c4c525 --- /dev/null +++ b/website/themes/router7/layouts/partials/head.html @@ -0,0 +1,14 @@ + + + + + + + + + {{ $sass := resources.Get "sass/sidebar.scss" }} + {{ $style := $sass | resources.ToCSS }} + + + {{ .Title }} + diff --git a/website/themes/router7/layouts/partials/header.html b/website/themes/router7/layouts/partials/header.html new file mode 100644 index 0000000..e69de29 diff --git a/website/themes/router7/layouts/partials/nav.html b/website/themes/router7/layouts/partials/nav.html new file mode 100644 index 0000000..58f4ccf --- /dev/null +++ b/website/themes/router7/layouts/partials/nav.html @@ -0,0 +1,15 @@ + diff --git a/website/themes/router7/theme.toml b/website/themes/router7/theme.toml new file mode 100644 index 0000000..551614b --- /dev/null +++ b/website/themes/router7/theme.toml @@ -0,0 +1,21 @@ +# theme.toml template for a Hugo theme +# See https://github.com/gohugoio/hugoThemes#themetoml for an example + +name = "Distri" +license = "MIT" +licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE" +description = "" +homepage = "http://example.com/" +tags = [] +features = [] +min_version = "0.41.0" + +[author] + name = "" + homepage = "" + +# If porting an existing theme +[original] + name = "" + homepage = "" + repo = ""