Skip to content

Commit 36e0036

Browse files
committed
qemu-script: Use a second bridge for an internal network
In the final setup we can use an internal L2 network and don't need to rely on ipvlan. This makes the QEMU setup resemble the final setup but still keeps the PXE/DHCP server on the host system, not in a VM. The required lokoctl binary comes from kinvolk/lokomotive#1317
1 parent 8d460e3 commit 36e0036

File tree

5 files changed

+98
-51
lines changed

5 files changed

+98
-51
lines changed

qemu-script/baremetal.lokocfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ cluster "bare-metal" {
1717
worker_names = var.worker_names
1818
# the user may append additional custom configs to the values: { for name, value in var.clc_snippets : name => concat(value, custom) }
1919
clc_snippets = { for name, paths in var.clc_snippets : name => [ for path in paths : file(path)] }
20+
network_ip_autodetection_method = "can-reach=${var.matchbox_addr}"
21+
2022
# Adds oidc flags to API server with default values.
2123
# Acts as a smoke test to check if API server is functional after addition
2224
# of extra flags.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# dnsmasq.conf
2+
3+
no-daemon
4+
dhcp-range={{DHCP_RANGE_LOW}},{{DHCP_RANGE_HIGH}},{{DHCP_NETMASK}}
5+
dhcp-option=3,{{DHCP_ROUTER_OPTION}}
6+
7+
log-queries
8+
log-dhcp
9+
10+
except-interface=lo
11+
interface={{BRIDGE_NAME}}
12+
bind-interfaces

qemu-script/dnsmasq.conf.template

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
no-daemon
44
dhcp-range={{DHCP_RANGE_LOW}},{{DHCP_RANGE_HIGH}},{{DHCP_NETMASK}}
5-
dhcp-option=3,{{DHCP_ROUTER_OPTION}}
65

76
enable-tftp
87
tftp-root=/var/lib/tftpboot

qemu-script/network.yaml.template

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,17 @@
11
networkd:
22
units:
3-
- name: zz-default.network
4-
dropins:
5-
- name: 10-priv-stable.conf
6-
contents: |
7-
[Match]
8-
MACAddress={{MAC}}
9-
# [Address]
10-
# Address=... # in case of static addressing on the interface
11-
[Network]
12-
# DHCP=no # in case of static
13-
IPVLAN=priv-stable
14-
- name: 10-priv-stable.netdev
15-
contents: |
16-
[NetDev]
17-
Description=Secondardy IP address for the default interface
18-
Name=priv-stable
19-
Kind=ipvlan
20-
[IPVLAN]
21-
Mode=L2
22-
Flags=bridge
233
- name: 10-priv-stable.network
244
contents: |
255
[Match]
26-
Name=priv-stable
6+
MACAddress={{MAC}}
277
[Link]
288
RequiredForOnline=no
29-
[Network]
30-
LinkLocalAddressing=no
319
[Address]
3210
Address={{IP_ADDRESS}}/24
3311
Scope=link
12+
[Network]
13+
DHCP=no
14+
LinkLocalAddressing=no
3415
storage:
3516
filesystems:
3617
- name: oem
@@ -44,7 +25,7 @@ storage:
4425
mode: 0644
4526
contents:
4627
inline: |
47-
set linux_append="flatcar.autologin ip={{IP_ADDRESS}}:::255.255.255.0::e*:none"
28+
set linux_append="flatcar.autologin"
4829
- path: /etc/hosts
4930
filesystem: root
5031
mode: 0644

qemu-script/prepare.sh

Lines changed: 79 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,43 @@ fi
1010

1111
if [ $# -lt 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
1212
echo "Usage: USE_QEMU=1 $0 create|destroy" # TODO: add something like create-image to embed an Ignition config into a Flatcar image for the mgmt node?
13+
echo "TODO: Make sure you disable any firewall, e.g., run sudo systemctl disable --now firewalld"
1314
exit 1
1415
fi
1516
# TODO: setup trap?
1617

18+
SCRIPTFOLDER="$(dirname "$(readlink -f "$0")")"
19+
cd "$SCRIPTFOLDER"
20+
1721
if [[ "${EUID}" -eq 0 ]]; then
1822
echo "Please do not run as root, sudo will be used where necessary"
1923
exit 1
2024
fi
2125

26+
27+
ls controller_macs worker_macs > /dev/null || { echo "Add at least one MAC address for each file controller_macs and worker_macs" ; exit 1 ; }
28+
2229
CONTROLLER_AMOUNT=1
2330
if [ -n "$USE_QEMU" ]; then
2431
VM_MEMORY=2500
2532
VM_DISK=10
26-
BRIDGE_NAME="pxe0"
27-
BRIDGE_ADDRESS="172.16.0.1" # TODO: use something smaller, for testing this is overlapping with the private IP address range until the "kernel_args" variable is exposed in Lokomotive to set up the private IP addr
28-
BRIDGE_SIZE="12"
29-
BRIDGE_BROADCAST="172.31.255.255"
30-
DHCP_RANGE_LOW="172.16.0.2"
31-
DHCP_RANGE_HIGH="172.31.255.254"
32-
DHCP_NETMASK="255.240.0.0"
33-
DHCP_ROUTER_OPTION="${BRIDGE_ADDRESS}"
33+
# Assign a wide subnet so that it overlaps with the actual subnet used internally, allowing to reach it from the host (later the range should be the same but split between static and dynamic to avoid conflicts)
34+
INTERNAL_BRIDGE_NAME="pxe0"
35+
INTERNAL_BRIDGE_ADDRESS="172.16.0.1"
36+
INTERNAL_BRIDGE_SIZE="12"
37+
INTERNAL_BRIDGE_BROADCAST="172.31.255.255"
38+
INTERNAL_DHCP_RANGE_LOW="172.16.0.2"
39+
INTERNAL_DHCP_RANGE_HIGH="172.31.255.254"
40+
INTERNAL_DHCP_NETMASK="255.240.0.0"
41+
# Set up Internet connectivity for the non-PXE interface of each VM
42+
EXTERNAL_BRIDGE_NAME="ext0"
43+
EXTERNAL_BRIDGE_ADDRESS="192.168.254.1"
44+
EXTERNAL_BRIDGE_SIZE="24"
45+
EXTERNAL_BRIDGE_BROADCAST="192.168.254.255"
46+
EXTERNAL_DHCP_RANGE_LOW="192.168.254.2"
47+
EXTERNAL_DHCP_RANGE_HIGH="192.168.254.254"
48+
EXTERNAL_DHCP_NETMASK="255.255.255.0"
49+
EXTERNAL_DHCP_ROUTER_OPTION="${EXTERNAL_BRIDGE_ADDRESS}"
3450
fi
3551

3652
# TODO: generate these two files ("ordered", e.g., sorting alphabetically?), ARP ping or ssh into ToR switch (and exclude mgmt node itself), also get BMC MAC addrs
@@ -88,27 +104,36 @@ function destroy_network() {
88104
echo "Destroying private ipvlan interface $(get_matchbox_interface)"
89105
sudo ip link delete "$(get_matchbox_interface)" type ipvlan || true
90106

91-
echo "Destroying network bridge ${BRIDGE_NAME}"
92-
sudo ip link delete "${BRIDGE_NAME}" type bridge || true
107+
echo "Destroying internal network bridge ${INTERNAL_BRIDGE_NAME}"
108+
sudo ip link delete "${INTERNAL_BRIDGE_NAME}" type bridge || true
109+
110+
echo "Destroying external network bridge ${EXTERNAL_BRIDGE_NAME}"
111+
sudo ip link delete "${EXTERNAL_BRIDGE_NAME}" type bridge || true
93112
fi
94113
}
95114

96115
function create_network() {
97116
destroy_network
98117
if [ -n "$USE_QEMU" ]; then
99-
echo "Creating bridge ${BRIDGE_NAME}"
118+
echo "Creating bridge ${EXTERNAL_BRIDGE_NAME}"
119+
120+
sudo ip link add name "${EXTERNAL_BRIDGE_NAME}" type bridge
121+
sudo ip link set "${EXTERNAL_BRIDGE_NAME}" up
122+
sudo ip addr add dev "${EXTERNAL_BRIDGE_NAME}" "${EXTERNAL_BRIDGE_ADDRESS}/${EXTERNAL_BRIDGE_SIZE}" broadcast "${EXTERNAL_BRIDGE_BROADCAST}"
123+
124+
echo "Creating bridge ${INTERNAL_BRIDGE_NAME}"
100125

101-
sudo ip link add name "${BRIDGE_NAME}" address aa:bb:cc:dd:ee:ff type bridge
102-
sudo ip link set "${BRIDGE_NAME}" up
126+
sudo ip link add name "${INTERNAL_BRIDGE_NAME}" address aa:bb:cc:dd:ee:ff type bridge
127+
sudo ip link set "${INTERNAL_BRIDGE_NAME}" up
103128
# Use a stable MAC address because it's the same that the matchbox interface gets, and we want to calculate a subnet from it # TODO: later create a VM with that MAC
104-
sudo ip addr add dev "${BRIDGE_NAME}" "${BRIDGE_ADDRESS}/${BRIDGE_SIZE}" broadcast "${BRIDGE_BROADCAST}"
129+
sudo ip addr add dev "${INTERNAL_BRIDGE_NAME}" "${INTERNAL_BRIDGE_ADDRESS}/${INTERNAL_BRIDGE_SIZE}" broadcast "${INTERNAL_BRIDGE_BROADCAST}"
105130

106131
echo "Creating private ipvlan interface $(get_matchbox_interface)"
107-
sudo ip link add name "$(get_matchbox_interface)" link "${BRIDGE_NAME}" type ipvlan mode l2
132+
sudo ip link add name "$(get_matchbox_interface)" link "${INTERNAL_BRIDGE_NAME}" type ipvlan mode l2
108133
sudo ip link set "$(get_matchbox_interface)" up
109134
sudo ip addr add dev "$(get_matchbox_interface)" "$(get_matchbox_ip_addr)/24"
110135

111-
# Setup NAT Internet access for the bridge
136+
# Setup NAT Internet access for the bridge (external, because the internal bridge DHCP does not announce a gateway)
112137
sudo iptables -P FORWARD ACCEPT
113138
sudo iptables -t nat -A POSTROUTING -o $(ip route get 1 | grep -o -P ' dev .*? ' | cut -d ' ' -f 3) -j MASQUERADE
114139

@@ -178,24 +203,45 @@ function destroy_containers() {
178203

179204
sudo docker stop dnsmasq || true
180205
sudo docker rm dnsmasq || true
206+
207+
208+
if [ -n "$USE_QEMU" ]; then
209+
sudo docker stop dnsmasq-external || true
210+
sudo docker rm dnsmasq-external || true
211+
fi
181212
}
182213

183-
# does DHCP/PXE
214+
# DHCP/PXE on the internal bridge
184215
function prepare_dnsmasq_conf() {
185216
local name="$(cluster_name)"
186217
[ -z "$name" ] && exit 1
187218

188219
mkdir -p ~/"lokoctl-assets/${name}/dnsmasq"
189220
sed \
190-
-e "s/{{DHCP_RANGE_LOW}}/$DHCP_RANGE_LOW/g" \
191-
-e "s/{{DHCP_RANGE_HIGH}}/$DHCP_RANGE_HIGH/g" \
192-
-e "s/{{DHCP_ROUTER_OPTION}}/$DHCP_ROUTER_OPTION/g" \
193-
-e "s/{{DHCP_NETMASK}}/$DHCP_NETMASK/g" \
194-
-e "s/{{BRIDGE_NAME}}/$BRIDGE_NAME/g" \
221+
-e "s/{{DHCP_RANGE_LOW}}/$INTERNAL_DHCP_RANGE_LOW/g" \
222+
-e "s/{{DHCP_RANGE_HIGH}}/$INTERNAL_DHCP_RANGE_HIGH/g" \
223+
-e "s/{{DHCP_NETMASK}}/$INTERNAL_DHCP_NETMASK/g" \
224+
-e "s/{{BRIDGE_NAME}}/$INTERNAL_BRIDGE_NAME/g" \
195225
-e "s/{{MATCHBOX}}/$(get_matchbox_ip_addr)/g" \
196226
< dnsmasq.conf.template > ~/"lokoctl-assets/${name}/dnsmasq/dnsmasq.conf"
197227
}
198228

229+
# regular DHCP on the external bridge (as libvirt would do)
230+
function prepare_dnsmasq_external_conf() {
231+
local name="$(cluster_name)"
232+
[ -z "$name" ] && exit 1
233+
234+
# TODO: add static IP addrs
235+
mkdir -p ~/"lokoctl-assets/${name}/dnsmasq"
236+
sed \
237+
-e "s/{{DHCP_RANGE_LOW}}/$EXTERNAL_DHCP_RANGE_LOW/g" \
238+
-e "s/{{DHCP_RANGE_HIGH}}/$EXTERNAL_DHCP_RANGE_HIGH/g" \
239+
-e "s/{{DHCP_ROUTER_OPTION}}/$EXTERNAL_DHCP_ROUTER_OPTION/g" \
240+
-e "s/{{DHCP_NETMASK}}/$EXTERNAL_DHCP_NETMASK/g" \
241+
-e "s/{{BRIDGE_NAME}}/$EXTERNAL_BRIDGE_NAME/g" \
242+
< dnsmasq-external.conf.template > ~/"lokoctl-assets/${name}/dnsmasq/dnsmasq-external.conf"
243+
}
244+
199245
function create_containers() {
200246
destroy_containers
201247
local name="$(cluster_name)"
@@ -220,6 +266,15 @@ function create_containers() {
220266
-v ~/"lokoctl-assets/${name}/dnsmasq/dnsmasq.conf:/etc/dnsmasq.conf:Z" \
221267
--net=host \
222268
quay.io/coreos/dnsmasq:v0.5.0 -d
269+
270+
prepare_dnsmasq_external_conf
271+
272+
sudo docker run --name dnsmasq-external \
273+
-d \
274+
--cap-add=NET_ADMIN \
275+
-v ~/"lokoctl-assets/${name}/dnsmasq/dnsmasq-external.conf:/etc/dnsmasq.conf:Z" \
276+
--net=host \
277+
quay.io/coreos/dnsmasq:v0.5.0 -d
223278
}
224279

225280
function destroy_nodes() {
@@ -245,7 +300,7 @@ function create_nodes() {
245300
local -r common_virt_opts="--memory=${VM_MEMORY} --vcpus=1 --disk pool=default,size=${VM_DISK} --os-type=linux --os-variant=generic --noautoconsole --events on_poweroff=preserve --boot=hd,network"
246301
echo "Creating nodes..."
247302
for num in $(seq 1 $NUM_NODES); do
248-
sudo virt-install --name "node${num}" --network=bridge:"${BRIDGE_NAME}",mac="${MAC_ADDRESS_LIST[$num - 1]}" ${common_virt_opts}
303+
sudo virt-install --name "node${num}" --network=bridge:"${INTERNAL_BRIDGE_NAME}",mac="${MAC_ADDRESS_LIST[$num - 1]}" --network=bridge:"${EXTERNAL_BRIDGE_NAME}" ${common_virt_opts}
249304
done
250305
else
251306
exit 1 # TODO: use ipmitool to force pxe
@@ -314,8 +369,6 @@ function gen_cluster_vars() {
314369
echo "worker_names = ${worker_names}" >> lokocfg.vars
315370
echo "matchbox_addr = \"$(get_matchbox_ip_addr)\"" >> lokocfg.vars
316371
echo "clc_snippets = ${clc_snippets}" >> lokocfg.vars
317-
# TODO: network_ip_autodetection_method = "can-reach=$MATCHBOX_IP"
318-
# TODO: kernel_args for matchbox ip=...
319372
}
320373

321374
if [ "$1" = create ]; then
@@ -352,7 +405,7 @@ if [ "$1" = create ]; then
352405
gen_cluster_vars
353406

354407
RET=0
355-
# TODO: currently requires imran/baremetal-add-clc-snippets
408+
# TODO: currently requires imran/baremetal-feature-parity
356409
"${HOME}"/kinvolk/lokomotive/lokoctl cluster apply --verbose --skip-components || RET=$?
357410

358411
if [ "$RET" = 0 ]; then

0 commit comments

Comments
 (0)