-
Notifications
You must be signed in to change notification settings - Fork 3
/
run_openwrt.sh
executable file
·226 lines (193 loc) · 9.54 KB
/
run_openwrt.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#!/usr/bin/env bash
# Based on https://github.com/qemus/qemu-docker
set -Eeuo pipefail
trap - ERR
. /var/vm/openwrt_metadata.conf
. /run/helpers.sh
. /run/install_openwrt_rootfs.sh
. /run/migrate_openwrt_rootfs.sh
# CPU architecture specific
CPU_ARCH=$(arch)
VERS=$(qemu-system-"$CPU_ARCH" --version | head -n 1 | cut -d '(' -f 1)
FILE=/storage/rootfs-${OPENWRT_IMAGE_ID}.img
# Attach physical interfaces to Docker container
attach_eth_if () {
HOST_IF=$1
CONTAINER_IF=$2
QEMU_IF=$3
# Privilige=true and pid=host mode necessary
# Sources
# * https://serverfault.com/questions/688483/assign-physical-interface-to-docker-exclusively
# * https://medium.com/lucjuggery/a-container-to-access-the-shell-of-the-host-2c7c227c64e9
# * https://developers.redhat.com/blog/2018/10/22/introduction-to-linux-interfaces-for-virtual-networking#
info "Attaching physical Ethernet interface $HOST_IF into container with the name $CONTAINER_IF ..."
# Check if interface exists
if ! nsenter --target 1 --uts --net --ipc --mount ip link show "$HOST_IF" &> /dev/null; then
info "Host Ethernet interface $HOST_IF does not exists. It can be a wrong interface name or the Ethernet interface is already assigend to this container."
return
fi
PID_CONTAINTER=$(nsenter --target 1 --uts --net --ipc --mount docker inspect -f '{{.State.Pid}}' $(cat /etc/hostname))
nsenter --target 1 --uts --net --ipc --mount mkdir -p /var/run/netns
nsenter --target 1 --uts --net --ipc --mount ln -s /proc/$PID_CONTAINTER/ns/net /var/run/netns/$PID_CONTAINTER
nsenter --target 1 --uts --net --ipc --mount ip link set $HOST_IF netns $PID_CONTAINTER name $CONTAINER_IF
nsenter --target 1 --uts --net --ipc --mount ip netns exec $PID_CONTAINTER ip link set $CONTAINER_IF up
nsenter --target 1 --uts --net --ipc --mount rm /var/run/netns/$PID_CONTAINTER
#ip link add link $CONTAINER_IF name $QEMU_IF type ipvlan mode l2
#ip link add link $CONTAINER_IF name $QEMU_IF type macvtap mode bridge
ip link add link $CONTAINER_IF name $QEMU_IF type macvtap mode passthru
# Create MAC address for new interface
QEMU_MAC_OUI="52:54:00"
read MAC </sys/class/net/$CONTAINER_IF/address
QEMU_IF_MAC=${QEMU_MAC_OUI}${MAC:8} # Replaces the 8 first characters of the original MAC
# Active new interface
ip link set $QEMU_IF address $QEMU_IF_MAC up
#ip link set $QEMU_IF up
}
# Create veth pairs between host system and Docker container
attach_veth_if () {
VETH_IF_HOST=$1
VETH_IF_CONTAINER=$2
QEMU_IF=$3
info "Creating virtual Ethernet interfaces pairs between host system ($VETH_IF_HOST) and container ($VETH_IF_CONTAINER)..."
if ! nsenter --target 1 --uts --net --ipc --mount ip link show "$VETH_IF_HOST" &> /dev/null; then
# Create veth pair
nsenter --target 1 --uts --net --ipc --mount ip link add $VETH_IF_HOST type veth peer name $VETH_IF_CONTAINER
nsenter --target 1 --uts --net --ipc --mount ip link set $VETH_IF_HOST up
if [[ -z "${IS_U_OS_APP}" ]]; then
nsenter --target 1 --uts --net --ipc --mount ip addr add 172.31.1.2/24 dev $VETH_IF_HOST
fi
else
info "Virtual Ethernet interface $VETH_IF_HOST already exists. Assuming pairs is already created."
fi
if nsenter --target 1 --uts --net --ipc --mount ip link show "$VETH_IF_CONTAINER" &> /dev/null; then
# Put second pair into container
PID_CONTAINTER=$(nsenter --target 1 --uts --net --ipc --mount docker inspect -f '{{.State.Pid}}' $(cat /etc/hostname))
nsenter --target 1 --uts --net --ipc --mount mkdir -p /var/run/netns
nsenter --target 1 --uts --net --ipc --mount ln -s /proc/$PID_CONTAINTER/ns/net /var/run/netns/$PID_CONTAINTER
nsenter --target 1 --uts --net --ipc --mount ip link set $VETH_IF_CONTAINER netns $PID_CONTAINTER
nsenter --target 1 --uts --net --ipc --mount ip netns exec $PID_CONTAINTER ip link set $VETH_IF_CONTAINER up
nsenter --target 1 --uts --net --ipc --mount rm /var/run/netns/$PID_CONTAINTER
ip link add link $VETH_IF_CONTAINER name $QEMU_IF type macvtap mode passthru
ip link set $QEMU_IF up
fi
# Only as u-OS app
if [[ -n "${IS_U_OS_APP}" ]]; then
# Check if u-OS webserver is already configured
if ! nsenter --target 1 --uts --net --ipc --mount grep -q "app-openwrt0" "/usr/lib/uc-http-server/ucu.yml" ; then
info "Adding app-openwrt0 to /usr/lib/uc-http-server/ucu.yml ..."
nsenter --target 1 --uts --net --ipc --mount mount -o remount,rw /
nsenter --target 1 --uts --net --ipc --mount sed -i "s/, 'usb-x1'/, 'usb-x1', 'app-openwrt0'/g" /usr/lib/uc-http-server/ucu.yml
nsenter --target 1 --uts --net --ipc --mount mount -o remount,ro /
fi
if ! nsenter --target 1 --uts --net --ipc --mount sh -c "test -f /var/lib/systemd/network/app-openwrt0.network"; then
info "Creating /var/lib/systemd/network/app-openwrt0.network ..."
nsenter --target 1 --uts --net --ipc --mount sh -c "echo '[Match]' > /var/lib/systemd/network/app-openwrt0.network"
nsenter --target 1 --uts --net --ipc --mount sh -c "echo 'Name=app-openwrt0' >> /var/lib/systemd/network/app-openwrt0.network"
nsenter --target 1 --uts --net --ipc --mount sh -c "echo '[Network]' >> /var/lib/systemd/network/app-openwrt0.network"
nsenter --target 1 --uts --net --ipc --mount sh -c "echo 'DHCP=yes' >> /var/lib/systemd/network/app-openwrt0.network"
nsenter --target 1 --uts --net --ipc --mount mount -o remount,rw /
nsenter --target 1 --uts --net --ipc --mount cp /var/lib/systemd/network/app-openwrt0.network /usr/lib/systemd/network/app-openwrt0.network
nsenter --target 1 --uts --net --ipc --mount mount -o remount,ro /
fi
if nsenter --target 1 --uts --net --ipc --mount ip link show app-openwrt0 &> /dev/null; then
info "Deleting previous app-openwrt0 Ethernet device ..."
nsenter --target 1 --uts --net --ipc --mount ip link del app-openwrt0
fi
info "Adding a bridge app-openwrt0 as workaround because uc-http-server cannot handle veths peer_ifindex "@ifXX" e.g. veth-openwrt0@if32"
nsenter --target 1 --uts --net --ipc --mount ip link add name app-openwrt0 type bridge
nsenter --target 1 --uts --net --ipc --mount ip link set dev app-openwrt0 up
nsenter --target 1 --uts --net --ipc --mount ip link set veth-openwrt0 master app-openwrt0
nsenter --target 1 --uts --net --ipc --mount systemctl restart uc-http-server
fi
}
# Handle dirfferent architectures
if [ $CPU_ARCH = "aarch64" ]; then
CPU_ARGS="-cpu cortex-a53 -M virt -bios /usr/share/qemu/edk2-aarch64-code.fd -vga none -device ramfb"
else
CPU_ARGS="-M pc -vga std"
fi
# Check KVM
info "Checking for KVM ..."
KVM_ERR=""
if [ ! -e /dev/kvm ]; then
KVM_ERR="(device file missing)"
else
if ! sh -c 'echo -n > /dev/kvm' &> /dev/null; then
KVM_ERR="(no write access)"
else
CPU_ARGS+=" --enable-kvm -cpu host"
info "KVM detected"
fi
fi
if [ -n "$KVM_ERR" ]; then
info "KVM acceleration not detected $KVM_ERR, this will cause a major loss of performance."
fi
# Attach physical PHY to container
LAN_ARGS=""
if [[ -z "${LAN_IF}" ]]; then
LAN_ARGS="-device virtio-net,netdev=qlan0 -netdev user,id=qlan0,net=192.168.1.0/24"
elif [[ $LAN_IF = "veth" ]]; then
attach_veth_if veth-openwrt0 veth1 qlan1
exec 30<>/dev/tap$(cat /sys/class/net/qlan1/ifindex)
LAN_ARGS="-device virtio-net-pci,netdev=hostnet0,mac=$(cat /sys/class/net/qlan1/address) \
-netdev tap,fd=30,id=hostnet0"
else
HOST_LAN_IF=$LAN_IF
attach_eth_if $HOST_LAN_IF $HOST_LAN_IF qlan0
exec 30<>/dev/tap$(cat /sys/class/net/qlan0/ifindex)
LAN_ARGS="-device virtio-net-pci,netdev=hostnet0,mac=$(cat /sys/class/net/qlan0/address) \
-netdev tap,fd=30,id=hostnet0"
fi
WAN_ARGS=""
if [[ -z "${WAN_IF}" || $WAN_IF = "host" ]]; then
WAN_ARGS="-device virtio-net,netdev=qwan0 -netdev user,id=qwan0,hostfwd=tcp::8000-:80,hostfwd=tcp::8022-:22"
elif [[ $WAN_IF = "none" ]]; then
WAN_ARGS=""
else
HOST_WAN_IF=$WAN_IF
attach_eth_if $HOST_WAN_IF $HOST_WAN_IF qwan0
exec 31<>/dev/tap$(cat /sys/class/net/qwan0/ifindex)
WAN_ARGS="-device virtio-net-pci,netdev=hostnet1,mac=$(cat /sys/class/net/qwan0/address) \
-netdev tap,fd=31,id=hostnet1"
fi
# Attach USB interface
USB_ARGS=""
USB_1_ARGS=""
USB_2_ARGS=""
if [[ -z "${USB_1}" ]]; then
USB_1_ARGS=""
else
USB_VID_1=$(echo $USB_1 | cut -d':' -f1)
USB_PID_1=$(echo $USB_1 | cut -d':' -f2)
USB_1_ARGS="-device usb-host,vendorid=0x$USB_VID_1,productid=0x$USB_PID_1"
fi
if [[ -z "${USB_2}" ]]; then
USB_2_ARGS=""
else
USB_VID_2=$(echo $USB_2 | cut -d':' -f1)
USB_PID_2=$(echo $USB_2 | cut -d':' -f2)
USB_2_ARGS="-device usb-host,vendorid=0x$USB_VID_2,productid=0x$USB_PID_2"
fi
USB_ARGS="${USB_1_ARGS} ${USB_2_ARGS}"
info "Booting image using $VERS..."
# See qemu command if debug is enabled
[[ "$DEBUG" == [Yy1]* ]] && set -x
#************************ FINAL BOOTING ************************
exec qemu-system-"$CPU_ARCH" \
-m 128 \
-nodefaults \
$CPU_ARGS -smp $CPU_COUNT \
-display vnc=:0,websocket=5700 \
-kernel /var/vm/kernel.bin -append "root=fe00 console=tty0" \
-blockdev driver=raw,node-name=hd0,cache.direct=on,file.driver=file,file.filename=${FILE} \
-device virtio-blk-pci,drive=hd0 \
-device qemu-xhci -device usb-kbd \
$LAN_ARGS \
$WAN_ARGS \
$USB_ARGS \
-qmp unix:/run/qmp-sock,server=on,wait=off \
-chardev socket,path=/run/qga.sock,server=on,wait=off,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
# -device virtio-net,netdev=qlan1 -netdev user,id=qlan1,net=192.168.1.0/24,hostfwd=tcp::8000-192.168.1.1:80 \
# -blockdev driver=raw,node-name=hd0,cache.direct=on,file.driver=file,file.filename=/var/vm/openwrt-armsr-armv8-generic-ext4-combined.img \