move README into (hugo-powered) website router7.org
This commit is contained in:
parent
1250211381
commit
cb95bb6df8
161
README.md
161
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 |
|
||||
|---|---|
|
||||
| `<public>:8053` | `dnsd` metrics (forwarded requests)
|
||||
| `<public>:8066` | `netconfigd` metrics (nftables counters)
|
||||
| `<private>:80` | gokrazy web interface
|
||||
| `<private>:67` | `dhcp4d`
|
||||
| `<private>:58` | `radvd`
|
||||
| `<private>:53` | `dnsd`
|
||||
| `<private>:8077` | `backupd` (serve backup.tar.gz)
|
||||
| `<private>:7733` | `diagd` (perform diagnostics)
|
||||
| `<private>:5022` | `captured` (serve captured packets)
|
||||
|
||||
Here’s an example of the diagd output:
|
||||
|
||||
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-diagd.png"
|
||||
width="800" alt="diagd output">
|
||||
|
||||
Here’s an example of the metrics when scraped with [Prometheus](https://prometheus.io/) and displayed in [Grafana](https://grafana.com/):
|
||||
|
||||
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-grafana.png"
|
||||
width="800" alt="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:
|
||||
|
||||
<img src="https://github.com/rtr7/router7/raw/master/devsetup.jpg"
|
||||
width="800" alt="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/)**
|
||||
|
1
docs/CNAME
Normal file
1
docs/CNAME
Normal file
@ -0,0 +1 @@
|
||||
router7.org
|
200
docs/architecture/index.html
Normal file
200
docs/architecture/index.html
Normal file
@ -0,0 +1,200 @@
|
||||
<!DOCTYPE html>
|
||||
<html> <head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous">
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://router7.org/sass/sidebar.css">
|
||||
|
||||
<title>router7: architecture</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-10"><nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#">router7</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav ml-auto">
|
||||
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="/">Home </a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link active" href="/architecture/">Architecture <span class="sr-only">(current)</span></a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="/installation/">Installation </a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="https://github.com/rtr7/router7">GitHub </a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 id="architecture">Architecture</h1>
|
||||
<p>router7 is based on <a href="https://gokrazy.org/">gokrazy</a>: 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.</p>
|
||||
<p>The individual services can be found in <a href="https://pkg.go.dev/github.com/rtr7/router7/cmd">github.com/rtr7/router7/cmd</a></p>
|
||||
<ul>
|
||||
<li>Each service runs in a separate process.</li>
|
||||
<li>Services communicate with each other by persisting state files. E.g., <code>cmd/dhcp4</code> writes <code>/perm/dhcp4/wire/lease.json</code>.</li>
|
||||
<li>A service notifies other services about state changes by sending them signal <code>SIGUSR1</code>.</li>
|
||||
</ul>
|
||||
<h2 id="configuration-files">Configuration files</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File</th>
|
||||
<th>Consumer(s)</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/perm/interfaces.json</code></td>
|
||||
<td><code>netconfigd</code></td>
|
||||
<td>Set IP/MAC addresses of <code>uplink0</code> and <code>lan0</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/perm/portforwardings.json</code></td>
|
||||
<td><code>netconfigd</code></td>
|
||||
<td>Configure nftables port forwarding rules</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/perm/dhcp6/duid</code></td>
|
||||
<td><code>dhcp6</code></td>
|
||||
<td>Set DHCP Unique Identifier (DUID) for obtaining static leases</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="state-files">State files</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>File</th>
|
||||
<th>Producer</th>
|
||||
<th>Consumer(s)</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/perm/dhcp4/wire/ack</code></td>
|
||||
<td><code>dhcp4</code></td>
|
||||
<td><code>dhcp4</code></td>
|
||||
<td>last DHCPACK packet for renewals across restarts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/perm/dhcp4/wire/lease.json</code></td>
|
||||
<td><code>dhcp4</code></td>
|
||||
<td><code>netconfigd</code></td>
|
||||
<td>Obtained DHCPv4 lease</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/perm/dhcp6/wire/lease.json</code></td>
|
||||
<td><code>dhcp6</code></td>
|
||||
<td><code>netconfigd</code>, <code>radvd</code></td>
|
||||
<td>Obtained DHCPv6 lease</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/perm/dhcp4d/leases.json</code></td>
|
||||
<td><code>dhcp4d</code></td>
|
||||
<td><code>dhcp4d</code>, <code>dnsd</code></td>
|
||||
<td>DHCPv4 leases handed out (including hostnames)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="available-ports">Available ports</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Port</th>
|
||||
<th>Purpose</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code><public>:8053</code></td>
|
||||
<td><code>dnsd</code> metrics (forwarded requests)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><public>:8066</code></td>
|
||||
<td><code>netconfigd</code> metrics (nftables counters)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:80</code></td>
|
||||
<td>gokrazy web interface</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:67</code></td>
|
||||
<td><code>dhcp4d</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:58</code></td>
|
||||
<td><code>radvd</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:53</code></td>
|
||||
<td><code>dnsd</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:8077</code></td>
|
||||
<td><code>backupd</code> (serve backup.tar.gz)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:7733</code></td>
|
||||
<td><code>diagd</code> (perform diagnostics)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code><private>:5022</code></td>
|
||||
<td><code>captured</code> (serve captured packets)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Here’s an example of <code>cmd/diagd</code> output:</p>
|
||||
<p><img src="https://github.com/rtr7/router7/raw/master/2018-07-14-diagd.png"
|
||||
width="800" alt="diagd output"></p>
|
||||
<p>Here’s an example of <code>cmd/netconfigd</code> metrics when scraped with <a href="https://prometheus.io/">Prometheus</a> and displayed in <a href="https://grafana.com/">Grafana</a>:</p>
|
||||
<p><img src="https://github.com/rtr7/router7/raw/master/2018-07-14-grafana.png"
|
||||
width="800" alt="metrics in grafana"></p>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<p class="small">
|
||||
© 2018 Michael Stapelberg and contributors
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<aside class="bd-toc">
|
||||
<nav id="TableOfContents">
|
||||
<ul>
|
||||
<li><a href="#configuration-files">Configuration files</a></li>
|
||||
<li><a href="#state-files">State files</a></li>
|
||||
<li><a href="#available-ports">Available ports</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
94
docs/index.html
Normal file
94
docs/index.html
Normal file
@ -0,0 +1,94 @@
|
||||
<!DOCTYPE html>
|
||||
<html> <head>
|
||||
<meta name="generator" content="Hugo 0.71.0-DEV" />
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous">
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://router7.org/sass/sidebar.css">
|
||||
|
||||
<title>router7: a small home internet router completely written in Go</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-10"><nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#">router7</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav ml-auto">
|
||||
|
||||
|
||||
|
||||
<a class="nav-item nav-link active" href="/">Home <span class="sr-only">(current)</span></a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="/architecture/">Architecture </a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="/installation/">Installation </a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="https://github.com/rtr7/router7">GitHub </a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 id="router7">router7</h1>
|
||||
<p>router7 is a pure-Go implementation of a small home internet router. It comes with all the services required to make a <a href="https://www.init7.net/en/internet/fiber7/">fiber7 internet connection</a> work (DHCPv4, DHCPv6, DNS, etc.).</p>
|
||||
<p>Note that this project should be considered a (working!) tech demo. Feature requests will likely not be implemented, and see <a href="CONTRIBUTING.md">CONTRIBUTING.md</a> for details about which contributions are welcome.</p>
|
||||
<h2 id="motivation">Motivation</h2>
|
||||
<p>Before starting router7, I was using the <a href="https://omnia.turris.cz/en/">Turris Omnia</a> router running OpenWrt. That worked fine up until May 2018, when an automated update pulled in a new version of <a href="https://git.openwrt.org/?p=project/odhcp6c.git;a=shortlog">odhcp6c</a>, OpenWrt’s DHCPv6 client. That version is incompatible with fiber7’s DHCP server setup (I think there are shortcomings on both sides).</p>
|
||||
<p>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.</p>
|
||||
<h2 id="project-goals">Project goals</h2>
|
||||
<ul>
|
||||
<li>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).</li>
|
||||
<li>Unit/integration tests use fiber7 packet capture files to minimize the chance of software changes breaking my connectivity.</li>
|
||||
<li>Safe and quick updates
|
||||
<ul>
|
||||
<li>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.</li>
|
||||
<li>Thanks to kexec, updates translate into merely 13s of internet connectivity loss.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Easy debugging
|
||||
<ul>
|
||||
<li>Configuration-related network packets (e.g. DHCP, IPv6 neighbor/router advertisements) are stored in a ring buffer which can be streamed into <a href="https://www.wireshark.org/">Wireshark</a>, allowing for live and retro-active debugging.</li>
|
||||
<li>The diagnostics daemon performs common diagnostic steps (ping, traceroute, …) for you.</li>
|
||||
<li>All state in the system is stored as human-readable JSON within the <code>/perm</code> partition and can be modified.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="hardware">Hardware</h2>
|
||||
<p>The reference hardware platform is the <a href="https://pcengines.ch/apu2c4.htm">PC Engines™ apu2c4</a> 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 <a href="https://pcengines.ch/msata16g.htm">msata16g</a> SSD module for reliable persistent storage and the <a href="https://pcengines.ch/usbcom1a.htm">usbcom1a</a> serial adapter if you don’t have one already.</p>
|
||||
<p>Other hardware might work, too, but is not tested.</p>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<p class="small">
|
||||
© 2018 Michael Stapelberg and contributors
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
146
docs/installation/index.html
Normal file
146
docs/installation/index.html
Normal file
@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html>
|
||||
<html> <head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous">
|
||||
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://router7.org/sass/sidebar.css">
|
||||
|
||||
<title>router7: installation</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-10"><nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#">router7</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav ml-auto">
|
||||
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="/">Home </a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="/architecture/">Architecture </a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link active" href="/installation/">Installation <span class="sr-only">(current)</span></a>
|
||||
|
||||
|
||||
<a class="nav-item nav-link " href="https://github.com/rtr7/router7">GitHub </a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 id="installation">Installation</h1>
|
||||
<p>Connect your serial adapter (<a href="https://pcengines.ch/usbcom1a.htm">usbcom1a</a> works well if you don’t have one already) to the apu2c4 and start a program to use it, e.g. <code>screen /dev/ttyUSB0 115200</code>. Then, power on the apu2c4 and configure it to do PXE boot:</p>
|
||||
<ul>
|
||||
<li>Press <code>F10</code> to enter the boot menu</li>
|
||||
<li>Press <code>3</code> to enter setup</li>
|
||||
<li>Press <code>n</code> to enable network boot</li>
|
||||
<li>Press <code>c</code> to move mSATA to the top of the boot order</li>
|
||||
<li>Press <code>e</code> to move iPXE to the top of the boot order</li>
|
||||
<li>Press <code>s</code> to save configuration and exit</li>
|
||||
</ul>
|
||||
<p>Connect a network cable on <code>net0</code>, the port closest to the serial console port:</p>
|
||||
<p><img src="https://github.com/rtr7/router7/raw/master/devsetup.jpg"
|
||||
width="800" alt="router7 development setup"></p>
|
||||
<p>Next, build a router7 image:</p>
|
||||
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="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<span style="color:#f92672">=</span>amd64 gokr-packer <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -hostname<span style="color:#f92672">=</span>router7 <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -overwrite_boot<span style="color:#f92672">=</span>/tmp/recovery/boot.img <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -overwrite_mbr<span style="color:#f92672">=</span>/tmp/recovery/mbr.img <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -overwrite_root<span style="color:#f92672">=</span>/tmp/recovery/root.img <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -kernel_package<span style="color:#f92672">=</span>github.com/rtr7/kernel <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -firmware_package<span style="color:#f92672">=</span>github.com/rtr7/kernel <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -gokrazy_pkgs<span style="color:#f92672">=</span>github.com/gokrazy/gokrazy/cmd/ntp <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> -serial_console<span style="color:#f92672">=</span>ttyS0,115200n8 <span style="color:#ae81ff">\
|
||||
</span><span style="color:#ae81ff"></span> github.com/rtr7/router7/cmd/...
|
||||
</code></pre></div><p>Run <code>rtr7-recover -boot=/tmp/recovery/boot.img -mbr=/tmp/recovery/mbr.img -root=/tmp/recovery/root.img</code> to:</p>
|
||||
<ul>
|
||||
<li>trigger a reset <a href="#rebootor">if a Teensy with the rebootor firmware is attached</a></li>
|
||||
<li>serve a DHCP lease to all clients which request PXE boot (i.e., your apu2c4)</li>
|
||||
<li>serve via TFTP:
|
||||
<ul>
|
||||
<li>the PXELINUX bootloader</li>
|
||||
<li>the router7 kernel</li>
|
||||
<li>an initrd archive containing the rtr7-recovery-init program and mke2fs</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>serve via HTTP the boot and root images</li>
|
||||
<li>optionally serve via HTTP a backup.tar.gz image containing files for <code>/perm</code> (e.g. for moving to new hardware, rolling back corrupted state, or recovering from a disk failure)</li>
|
||||
<li>exit once the router successfully wrote the images to disk</li>
|
||||
</ul>
|
||||
<h2 id="updates">Updates</h2>
|
||||
<p>Run e.g. <code>rtr7-safe-update -updates_dir=$HOME/router7/updates</code> to:</p>
|
||||
<ul>
|
||||
<li>verify the router currently has connectivity, abort the update otherwise</li>
|
||||
<li>download a backup archive of <code>/perm</code></li>
|
||||
<li>build a new image</li>
|
||||
<li>update the router</li>
|
||||
<li>wait until the router restored connectivity, roll back the update using <code>rtr7-recover</code> otherwise</li>
|
||||
</ul>
|
||||
<p>The update step uses kexec to reduce the downtime to approximately 15 seconds.</p>
|
||||
<h2 id="manual-recovery">Manual Recovery</h2>
|
||||
<p>Given <code>rtr7-safe-update</code>’s safeguards, manual recovery should rarely be required.</p>
|
||||
<p>To manually roll back to an older image, invoke <code>rtr7-safe-update</code> via the
|
||||
<code>recover.bash</code> script in the image directory underneath <code>-updates_dir</code>, e.g.:</p>
|
||||
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell">% cd ~/router7/updates/2018-07-03T17:33:52+02:00
|
||||
% ./recover.bash
|
||||
</code></pre></div><h2 id="rebootor">Teensy rebootor</h2>
|
||||
<p>The cheap and widely-available <a href="https://www.pjrc.com/store/teensypp.html">Teensy++ USB development board</a> comes with a firmware called rebootor, which is used by the <a href="https://www.pjrc.com/teensy/loader_cli.html"><code>teensy_loader_cli</code></a> program to perform hard resets.</p>
|
||||
<p>This setup can be used to programmatically reset the apu2c4 (from <code>rtr7-recover</code>) by connecting the Teensy++ to the <a href="http://pcengines.ch/pdf/apu2.pdf">apu2c4’s reset pins</a>:</p>
|
||||
<ul>
|
||||
<li>connect the Teensy++’s <code>GND</code> pin to the apu2c4 J2’s pin 4 (<code>GND</code>)</li>
|
||||
<li>connect the Teensy++’s <code>B7</code> pin to the apu2c4 J2’s pin 5 (<code>3.3V</code>, resets when pulled to <code>GND</code>)</li>
|
||||
</ul>
|
||||
<p>You can find a working rebootor firmware .hex file at <a href="https://github.com/PaulStoffregen/teensy_loader_cli/issues/38">https://github.com/PaulStoffregen/teensy_loader_cli/issues/38</a></p>
|
||||
<h2 id="prometheus">Prometheus</h2>
|
||||
<p>See <a href="https://github.com/rtr7/router7/tree/master/contrib/prometheus">https://github.com/rtr7/router7/tree/master/contrib/prometheus</a> for example
|
||||
configuration files, and install the <a href="https://grafana.com/dashboards/8288">router7 Grafana
|
||||
Dashboard</a>.</p>
|
||||
|
||||
|
||||
<hr>
|
||||
|
||||
<p class="small">
|
||||
© 2018 Michael Stapelberg and contributors
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<aside class="bd-toc">
|
||||
<nav id="TableOfContents">
|
||||
<ul>
|
||||
<li><a href="#updates">Updates</a></li>
|
||||
<li><a href="#manual-recovery">Manual Recovery</a></li>
|
||||
<li><a href="#rebootor">Teensy rebootor</a></li>
|
||||
<li><a href="#prometheus">Prometheus</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
</html>
|
2
docs/robots.txt
Normal file
2
docs/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
sitemap: https://router7.org/sitemap.xml
|
19
docs/sass/sidebar.css
Normal file
19
docs/sass/sidebar.css
Normal file
@ -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; }
|
17
docs/sitemap.xml
Normal file
17
docs/sitemap.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<url>
|
||||
<loc>https://router7.org/</loc>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://router7.org/architecture/</loc>
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://router7.org/installation/</loc>
|
||||
</url>
|
||||
|
||||
</urlset>
|
6
website/archetypes/default.md
Normal file
6
website/archetypes/default.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
title: "{{ replace .Name "-" " " | title }}"
|
||||
date: {{ .Date }}
|
||||
draft: true
|
||||
---
|
||||
|
19
website/config.toml
Normal file
19
website/config.toml
Normal file
@ -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. <img> tags in markdown articles.
|
||||
unsafe = true
|
||||
|
||||
[menu]
|
||||
|
||||
[[menu.main]]
|
||||
name = "github"
|
||||
title = "GitHub"
|
||||
url = "https://github.com/rtr7/router7"
|
||||
weight = 60
|
37
website/content/_index.md
Normal file
37
website/content/_index.md
Normal file
@ -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.
|
58
website/content/architecture.md
Normal file
58
website/content/architecture.md
Normal file
@ -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 |
|
||||
|---|---|
|
||||
| `<public>:8053` | `dnsd` metrics (forwarded requests)
|
||||
| `<public>:8066` | `netconfigd` metrics (nftables counters)
|
||||
| `<private>:80` | gokrazy web interface
|
||||
| `<private>:67` | `dhcp4d`
|
||||
| `<private>:58` | `radvd`
|
||||
| `<private>:53` | `dnsd`
|
||||
| `<private>:8077` | `backupd` (serve backup.tar.gz)
|
||||
| `<private>:7733` | `diagd` (perform diagnostics)
|
||||
| `<private>:5022` | `captured` (serve captured packets)
|
||||
|
||||
Here’s an example of `cmd/diagd` output:
|
||||
|
||||
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-diagd.png"
|
||||
width="800" alt="diagd output">
|
||||
|
||||
Here’s an example of `cmd/netconfigd` metrics when scraped with [Prometheus](https://prometheus.io/) and displayed in [Grafana](https://grafana.com/):
|
||||
|
||||
<img src="https://github.com/rtr7/router7/raw/master/2018-07-14-grafana.png"
|
||||
width="800" alt="metrics in grafana">
|
93
website/content/installation.md
Normal file
93
website/content/installation.md
Normal file
@ -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:
|
||||
|
||||
<img src="https://github.com/rtr7/router7/raw/master/devsetup.jpg"
|
||||
width="800" alt="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).
|
2
website/layouts/robots.txt
Normal file
2
website/layouts/robots.txt
Normal file
@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
sitemap: https://router7.org/sitemap.xml
|
@ -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; }
|
@ -0,0 +1 @@
|
||||
{"Target":"sass/sidebar.css","MediaType":"text/css","Data":{}}
|
1
website/static/CNAME
Normal file
1
website/static/CNAME
Normal file
@ -0,0 +1 @@
|
||||
router7.org
|
20
website/themes/router7/LICENSE
Normal file
20
website/themes/router7/LICENSE
Normal file
@ -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.
|
2
website/themes/router7/archetypes/default.md
Normal file
2
website/themes/router7/archetypes/default.md
Normal file
@ -0,0 +1,2 @@
|
||||
+++
|
||||
+++
|
23
website/themes/router7/assets/sass/sidebar.scss
Normal file
23
website/themes/router7/assets/sass/sidebar.scss
Normal file
@ -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;
|
||||
}
|
0
website/themes/router7/layouts/404.html
Normal file
0
website/themes/router7/layouts/404.html
Normal file
17
website/themes/router7/layouts/_default/baseof.html
Normal file
17
website/themes/router7/layouts/_default/baseof.html
Normal file
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
{{- partial "head.html" . -}}
|
||||
<body>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
|
||||
{{- partial "header.html" . -}}
|
||||
|
||||
{{ block "main" . }}
|
||||
{{ end }}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{{- partial "footer.html" . -}}
|
||||
</body>
|
||||
</html>
|
31
website/themes/router7/layouts/_default/list.html
Normal file
31
website/themes/router7/layouts/_default/list.html
Normal file
@ -0,0 +1,31 @@
|
||||
{{ define "main" }}
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
|
||||
{{- partial "nav.html" . -}}
|
||||
{{ .Content }}
|
||||
|
||||
<h1>list template</h1>
|
||||
|
||||
<ul>
|
||||
{{ range .Pages }}
|
||||
<li>
|
||||
<a href="{{ .Permalink }}">{{ .Title }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<p class="small">
|
||||
© 2018 Michael Stapelberg and contributors
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<aside class="bd-toc">
|
||||
{{ .TableOfContents }}
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
||||
|
20
website/themes/router7/layouts/_default/single.html
Normal file
20
website/themes/router7/layouts/_default/single.html
Normal file
@ -0,0 +1,20 @@
|
||||
{{ define "main" }}
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
|
||||
{{- partial "nav.html" . -}}
|
||||
{{ .Content }}
|
||||
|
||||
<hr>
|
||||
|
||||
<p class="small">
|
||||
© 2018 Michael Stapelberg and contributors
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<aside class="bd-toc">
|
||||
{{ .TableOfContents }}
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
17
website/themes/router7/layouts/index.html
Normal file
17
website/themes/router7/layouts/index.html
Normal file
@ -0,0 +1,17 @@
|
||||
{{ define "main" }}
|
||||
<div class="row">
|
||||
<div class="col-md-10">
|
||||
|
||||
{{- partial "nav.html" . -}}
|
||||
{{ .Content }}
|
||||
|
||||
<hr>
|
||||
|
||||
<p class="small">
|
||||
© 2018 Michael Stapelberg and contributors
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
</div>
|
||||
</div>
|
||||
{{ end }}
|
7
website/themes/router7/layouts/partials/footer.html
Normal file
7
website/themes/router7/layouts/partials/footer.html
Normal file
@ -0,0 +1,7 @@
|
||||
<!-- Optional JavaScript -->
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
14
website/themes/router7/layouts/partials/head.html
Normal file
14
website/themes/router7/layouts/partials/head.html
Normal file
@ -0,0 +1,14 @@
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" crossorigin="anonymous">
|
||||
|
||||
{{ $sass := resources.Get "sass/sidebar.scss" }}
|
||||
{{ $style := $sass | resources.ToCSS }}
|
||||
<link rel="stylesheet" href="{{ $style.Permalink }}">
|
||||
|
||||
<title>{{ .Title }}</title>
|
||||
</head>
|
0
website/themes/router7/layouts/partials/header.html
Normal file
0
website/themes/router7/layouts/partials/header.html
Normal file
15
website/themes/router7/layouts/partials/nav.html
Normal file
15
website/themes/router7/layouts/partials/nav.html
Normal file
@ -0,0 +1,15 @@
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#">router7</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
|
||||
<div class="navbar-nav ml-auto">
|
||||
{{ $current := . }}
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ $active := $current.IsMenuCurrent "main" . }}
|
||||
<a class="nav-item nav-link {{ if $active }}active{{ end }}" href="{{ .URL }}">{{ .Title }} {{ if $active }}<span class="sr-only">(current)</span>{{ end }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
21
website/themes/router7/theme.toml
Normal file
21
website/themes/router7/theme.toml
Normal file
@ -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 = ""
|
Loading…
x
Reference in New Issue
Block a user