Merge pull request #1 from oofnikj/rpi-zero

Add support for ARM (Raspberry Pi)
pull/2/head
oofnikj 2020-04-17 16:21:48 +03:00 committed by GitHub
commit e9d5e789f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 20 deletions

12
Dockerfile.rpi 100644
View File

@ -0,0 +1,12 @@
FROM scratch
COPY . .
ARG ROOT_PW
RUN echo -e "${ROOT_PW}\n${ROOT_PW}" | passwd
RUN mkdir -p /var/lock
RUN opkg update && \
opkg install \
iperf3 \
ip-full && \
opkg list-upgradable | awk '{print $1}' | xargs opkg upgrade
CMD [ "/sbin/init" ]

View File

@ -1,13 +1,17 @@
.PHONY: build run clean install uninstall
.PHONY: build build-rpi run clean install uninstall
include openwrt.conf
export
build:
@docker build \
--build-arg ROOT_PW=${ROOT_PW} \
--build-arg OPENWRT_TAG=${OPENWRT_TAG} \
docker build \
--build-arg ROOT_PW \
--build-arg OPENWRT_TAG \
-t ${BUILD_TAG} .
build-rpi:
./build-rpi.sh ${RPI_SOURCE_IMG}
run:
./run.sh

View File

@ -1,8 +1,8 @@
# OpenWRT in Docker
# OpenWrt in Docker
Inspired by other projects that run `hostapd` in a Docker container. This goes one step further and boots a full network OS intended for embedded devices called [OpenWRT](https://openwrt.org/), so you can manage all aspects of your network from a user-friendly web UI.
Inspired by other projects that run `hostapd` in a Docker container. This goes one step further and boots a full network OS intended for embedded devices called [OpenWrt](https://openwrt.org/), so you can manage all aspects of your network from a user-friendly web UI.
I only tested this on x86_64, but it might work on ARM too with some minor tweaking.
For Raspberry Pi-specific build instructions, see [Building on Raspberry Pi](./rpi.md).
## Dependencies
@ -17,13 +17,13 @@ I only tested this on x86_64, but it might work on ARM too with some minor tweak
```
$ make build
```
If you want additional OpenWRT packages to be present in the base image, add them to the Dockerfile. Otherwise you can install them with `opkg` after bringing up the container.
If you want additional OpenWrt packages to be present in the base image, add them to the Dockerfile. Otherwise you can install them with `opkg` after bringing up the container.
A searchable package list is available on [openwrt.org](https://openwrt.org/packages/table/start).
## Configure
Initial configuration is performed using a config file, `openwrt.conf`. Values read from this file at runtime are used to generate OpenWRT format config files.
Initial configuration is performed using a config file, `openwrt.conf`. Values read from this file at runtime are used to generate OpenWrt format config files.
To add or change the base configuration, modify the config templates in `etc/config/<section>.tpl`.
@ -58,10 +58,8 @@ This will delete the container and all associated Docker networks so you can sta
### Hairpinning
This took a couple of tries to get working. The most challenging issue was getting traffic from WLAN clients to reach each other.
In order for this to work, OpenWRT bridges all interfaces in the LAN zone and sets hairpin mode (aka [reflective relay](https://lwn.net/Articles/347344/)) on the WLAN interface, meaning packets arriving on that interface can be 'reflected' back out through the same interface.
OpenWRT is not able to set this mode from inside the container even with `NET_ADMIN` capabilities, so this must be done from the host.
In order for WLAN clients to see one another, OpenWrt bridges all interfaces in the LAN zone and sets hairpin mode (aka [reflective relay](https://lwn.net/Articles/347344/)) on the WLAN interface, meaning packets arriving on that interface can be 'reflected' back out through the same interface.
`run.sh` tries to handle this, and prints a warning if it fails.

41
build-rpi.sh 100755
View File

@ -0,0 +1,41 @@
#!/bin/bash
# Extracts the rootfs from OpenWRT Raspberry Pi image available from
# https://downloads.openwrt.org/releases/19.07.2/targets/brcm2708/bcm2708/
# and builds a Docker container out of it
#
# Refer to https://openwrt.org/toh/raspberry_pi_foundation/raspberry_pi
# to choose the right image
#
# If building on x86, you must have qemu-arm and binfmt-support installed
set -e
IMG=${1:-'x'}
mount_rootfs() {
echo "* mounting image"
offset=$(sfdisk -d ${IMG} | grep "${IMG}2" | sed -E 's/.*start=\s+([0-9]+).*/\1/g')
tmpdir=$(mktemp -u -p .)
mkdir -p "${tmpdir}"
sudo mount -o loop,offset=$((512 * $offset)) -t ext4 ${IMG} ${tmpdir}
}
docker_build() {
echo "* building Docker image"
sudo docker build \
--build-arg ROOT_PW="${ROOT_PW}" \
-t ${BUILD_TAG} -f Dockerfile.rpi ${tmpdir}
}
cleanup() {
echo "* cleaning up"
sudo umount ${tmpdir}
rm -rf ${tmpdir}
}
test -f ${IMG} || { echo 'no image file found'; exit 1; }
trap cleanup EXIT
mount_rootfs
docker_build

View File

@ -1,24 +1,31 @@
### Sample OpenWRT config file ###
# general
## general
# source image for Raspberry Pi build target
SOURCE_IMG=openwrt-19.07.2-brcm2708-bcm2708-rpi-ext4-factory.img
# source tag for build (x86) target
OPENWRT_TAG=x86-64-19.07.2
# final tag for built Docker image
BUILD_TAG=openwrt
# container name
CONTAINER=openwrt_1
ROOT_PW=changeme123
# docker network settings
# wan
WAN_NAME=openwrt-wan
WAN_PARENT=enp0s20f0u4
# host interface which will provide the WAN link for OpenWRT
WAN_PARENT=eth0
UPSTREAM_DNS_SERVER=8.8.8.8
# lan
# Static IP address configuration for OpenWRT LAN
LAN_NAME=openwrt-lan
LAN_DOMAIN=home
LAN_SUBNET=192.168.16.0/24
LAN6_SUBNET=fd99:1234::/48
# Set LAN_ADDR to something other than the first available address
# in the subnet - Docker will claim this address for the host
LAN_ADDR=192.168.16.2
LAN_HOST=192.168.16.1
# openwrt doesn't accept CIDR notation; must match LAN_SUBNET
LAN_NETMASK=255.255.255.0

34
rpi.md 100644
View File

@ -0,0 +1,34 @@
# Building on Raspberry Pi
Turn your Pi into a pretty okay-ish travel router (or a very slow main router)!
OpenWrt officially supports Raspberry Pi hardware if you want to run it as your OS. But running in a container brings many advantages, one of which is not having to re-flash your SD card.
This has been tested on a Raspberry Pi Zero W running Raspbian Lite, but should work for other versions too. Just make sure you download the right image for your Pi version (refer to the notes in [build-rpi.sh](./build-rpi.sh)).
## IPv6
By default Raspbian does not load the kernel module for IPv6 `iptables` on boot.
Run `sudo modprobe ip6_tables` to load it immediately.
To persist on reboot, run
$ echo 'ip6_tables' | sudo tee /etc/modules-load.d/ip6-tables.conf
---
## Build
You can build the OpenWRT docker image on the Pi itself, or on your x86 PC with `qemu-arm` installed.
First download and extract the OpenWRT factory image for your Pi. Refer to the [OpenWrt Table of Hardware](https://openwrt.org/toh/raspberry_pi_foundation/raspberry_pi) to choose the right image. Then run the `make` target.
The variable `RPI_SOURCE_IMG` can be specified in openwrt.conf or on the command line:
```
$ https://downloads.openwrt.org/releases/19.07.2/targets/brcm2708/bcm2708/openwrt-19.07.2-brcm2708-bcm2708-rpi-ext4-factory.img.gz
$ gzip -d openwrt-*.img.gz
$ make build-rpi RPI_SOURCE_IMG=openwrt-19.07.2-brcm2708-bcm2708-rpi-ext4-factory.img
```
If you built the image on your PC, send it to your Raspberry Pi (`$BUILD_TAG` is a config variable):
```
$ docker save $BUILD_TAG | ssh <your_raspberry_pi_host> docker load

20
run.sh
View File

@ -69,7 +69,7 @@ function _set_hairpin() {
for i in {1..10}; do
echo -n '.'
sudo ip netns exec $CONTAINER ip link set $WIFI_IFACE type bridge_slave hairpin on 2>/dev/null && { echo 'ok'; break; }
sleep 1
sleep 3
done
if [[ $i -ge 10 ]]; then
echo -e "\ncouldn't set hairpin mode, wifi clients will probably be unable to talk to each other"
@ -78,8 +78,8 @@ function _set_hairpin() {
function _create_or_start_container() {
docker inspect $BUILD_TAG >/dev/null 2>&1 || { echo "no image '$BUILD_TAG' found, did you forget to run 'make build'?"; exit 1; }
docker inspect $CONTAINER >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
if docker inspect $CONTAINER >/dev/null 2>&1; then
echo "* starting container '$CONTAINER'"
docker start $CONTAINER
else
@ -103,9 +103,20 @@ function _create_or_start_container() {
fi
}
function _reload_fw() {
echo "* reloading firewall rules"
docker exec -it $CONTAINER sh -c '
for iptables in iptables ip6tables; do
for table in filter nat mangle; do
$iptables -t $table -F
done
done
/sbin/fw3 -q restart'
}
function main() {
test -z $WIFI_IFACE && _usage
cd $SCRIPT_DIR
cd "${SCRIPT_DIR}"
_get_phy_from_dev
_nmcli
_create_or_start_container
@ -124,6 +135,7 @@ function main() {
echo "* getting address via DHCP"
sudo dhcpcd -q "br-${LAN_ID:0:12}"
_reload_fw
echo "* ready"
}