[COMMIT osv master] firecracker: improve networking setup tools

6 views
Skip to first unread message

Commit Bot

unread,
Nov 2, 2019, 10:16:51 AM11/2/19
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <jwkoz...@gmail.com>
Branch: master

firecracker: improve networking setup tools

This patch is slightly more enhanced version of the patch
submitted originally by Zhiting Zhu.

It mainly adds number of new scripts aiming to help setup
proper networking environment for OSv on firecracker:

- setup_fc_networking.sh - top-level script that orchestrates networking
setup and delegates to other scripts; called from firecracker.py
- create_tap_device.sh - creates TAP device setup with NAT or bridge
- setup_dnsmasq.sh - sets up and starts dnsmasq service to provide DNS setup
for outgoing traffic
- setup_iptables.sh - sets up IP tables to allow for outgoing traffic
between TAP and
selected physical NIC
- restore_iptables.sh - restores IP tables to the state before
setup_iptables.sh called
- remove_dnsmasq.sh - destroys dnsmasq setup created by setup_dnsmasq.sh

This script also refactors firecracker.py to delegate networking setup
to setup_fc_networking.sh.

For more information about NAT, bridging and firecracker
read those:
-
https://jamielinux.com/docs/libvirt-networking-handbook/custom-nat-based-network.html
-
https://github.com/firecracker-microvm/firecracker/blob/master/docs/network-setup.md

Signed-off-by: Zhiting Zhu <zhit...@cs.utexas.edu>
Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>

---
diff --git a/scripts/create_tap_device.sh b/scripts/create_tap_device.sh
--- a/scripts/create_tap_device.sh
+++ b/scripts/create_tap_device.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+MODE=$1
+TAP_INTERFACE=$2
+TAP_IP=$3
+BRIDGE_NAME=$3
+
+usage()
+{
+ cat <<-EOF
+Usage: $0 <mode> <tap_device_name> <tap_IP> | <bridge_name>
+creates TAP device
+mode can be: 'bridged' or 'natted'(the default)
+To delete TAP device: sudo ip link set <tap_device_name> down
+EOF
+}
+
+if [ "$#" -ne 3 ]; then
+ usage
+ exit 1
+fi
+
+ip link show "$TAP_INTERFACE" 1>/dev/null 2>/dev/null
+
+if [ $? != 0 ]; then
+ sudo ip tuntap add dev "$TAP_INTERFACE" mode tap
+ sudo sysctl -q -w net.ipv4.conf.$TAP_INTERFACE.proxy_arp=1
+ sudo sysctl -q -w net.ipv6.conf.$TAP_INTERFACE.disable_ipv6=1
+ sudo ip link set dev "$TAP_INTERFACE" up
+
+ if [ "$MODE" == "bridged" ] && [ "$BRIDGE_NAME" != "" ]; then
+ sudo brctl addif "$BRIDGE_NAME" "$TAP_INTERFACE"
+ else
+ sudo ip addr add "$TAP_IP/30" dev "$TAP_INTERFACE"
+ fi
+else
+ echo "The tap device $TAP_INTERFACE already exists"
+ exit 0
+fi
diff --git a/scripts/firecracker.py b/scripts/firecracker.py
--- a/scripts/firecracker.py
+++ b/scripts/firecracker.py
@@ -135,29 +135,28 @@ def print_time(msg):
print("%s: %s" % (now.isoformat(), msg))


-def setup_tap_interface(tap_interface_name, tap_ip, bridge_name):
+def setup_tap_interface(mode, tap_interface_name, tap_ip=None,
physical_nic=None, bridge_name=None):
# Setup tun tap interface if does not exist
# sudo ip link delete fc_tap0 - this deletes the tap device
tuntap_interfaces = subprocess.check_output(['ip', 'tuntap'])
if tuntap_interfaces.find(tap_interface_name) < 0:
print("The tap interface %s not found -> needs to set it up!" %
tap_interface_name)
+ dirname = os.path.dirname(os.path.abspath(__file__))
+ setup_networking_script =
os.path.join(dirname, 'setup_fc_networking.sh')
# Check if the bridge exists if user specified it
- if bridge_name:
+ if mode == 'bridged' and bridge_name:
bridges = subprocess.check_output(['brctl', 'show'])
if bridges.find(bridge_name) < 0:
print("The bridge %s does not exist per brctl. Please
create one!" % bridge_name)
exit(-1)
-
- subprocess.call(['sudo', 'ip', 'tuntap', 'add', 'dev',
tap_interface_name, 'mode', 'tap'])
-
subprocess.call(['sudo', 'sysctl', '-q', '-w', 'net.ipv4.conf.%s.proxy_arp=1' %
tap_interface_name])
-
subprocess.call(['sudo', 'sysctl', '-q', '-w', 'net.ipv6.conf.%s.disable_ipv6=1' %
tap_interface_name])
- subprocess.call(['sudo', 'ip', 'link', 'set', 'dev',
tap_interface_name, 'up'])
-
- if bridge_name:
- subprocess.call(['sudo', 'brctl', 'addif', bridge_name,
tap_interface_name])
+ print("Setting up TAP device in bridged mode!")
+ subprocess.call([setup_networking_script, 'bridged',
tap_interface_name, bridge_name])
else:
- subprocess.call(['sudo', 'ip', 'addr', 'add', '%s/30' %
tap_ip, 'dev', tap_interface_name])
-
+ print("Setting up TAP device in natted mode!")
+ if physical_nic is not None:
+ subprocess.call([setup_networking_script, 'natted',
tap_interface_name, tap_ip, physical_nic])
+ else:
+ subprocess.call([setup_networking_script, 'natted',
tap_interface_name, tap_ip])

def find_firecracker(dirname):
firecracker_path = os.path.join(dirname, '../.firecracker/firecracker')
@@ -264,11 +263,14 @@ def main(options):
cmdline = "--nopci %s" % cmdline

if options.networking:
- tap_ip = '172.16.0.1'
- setup_tap_interface('fc_tap0', tap_ip, options.bridge)
+ tap_device = 'fc_tap0'
if not options.bridge:
+ tap_ip = '172.16.0.1'
client_ip = '172.16.0.2'
- cmdline = '--ip=eth0,%s,255.255.255.252 --defaultgw=%s %s' %
(client_ip, tap_ip, cmdline)
+ cmdline = '--ip=eth0,%s,255.255.255.252 --defaultgw=%s
--nameserver=%s %s' % (client_ip, tap_ip, tap_ip, cmdline)
+ setup_tap_interface('natted', tap_device, tap_ip,
options.physical_nic)
+ else:
+ setup_tap_interface('bridged', tap_device, None, None,
options.bridge)

if options.verbose:
cmdline = '--verbose ' + cmdline
@@ -346,6 +348,8 @@ def main(options):
help="pass --verbose to OSv, to display more
debugging information on the console")
parser.add_argument("-l", "--api_less", action="store_true",
help="do NOT use socket-based API to configure and
start OSv on firecracker")
+ parser.add_argument("-p", "--physical_nic", action="store",
default=None,
+ help="name of the physical NIC (wired or wireless)
to forward to if in natted mode")

cmd_args = parser.parse_args()
if cmd_args.verbose:
diff --git a/scripts/remove_dnsmasq.sh b/scripts/remove_dnsmasq.sh
--- a/scripts/remove_dnsmasq.sh
+++ b/scripts/remove_dnsmasq.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ "$#" -ne 1 ]; then
+ echo "Usage: $0 <NIC>"
+ echo "Deletes DNSmasq configuration file"
+ exit 1
+fi
+
+DEV=$1
+sudo rm -rf /var/lib/dnsmasq/$DEV
+sudo rm -rf /etc/dnsmasq.d/$DEV.conf
diff --git a/scripts/restore_iptables.sh b/scripts/restore_iptables.sh
--- a/scripts/restore_iptables.sh
+++ b/scripts/restore_iptables.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+FILE="/tmp/osv_iptables.rules.old"
+
+if [ -f "$FILE" ]; then
+ sudo iptables-restore < "$FILE"
+ sudo rm "$FILE"
+fi
+sudo sh -c "echo 0 > /proc/sys/net/ipv4/ip_forward"
diff --git a/scripts/setup_dnsmasq.sh b/scripts/setup_dnsmasq.sh
--- a/scripts/setup_dnsmasq.sh
+++ b/scripts/setup_dnsmasq.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+# Configures local light DNS service for specified NIC
+if [ "$#" -ne 1 ]; then
+ echo "Usage: $0 <NIC>"
+ exit 1
+fi
+DEV=$1
+
+if [ ! -d "/var/lib/dnsmasq/$DEV" ]; then
+ sudo mkdir -p /var/lib/dnsmasq/$DEV
+ sudo touch /var/lib/dnsmasq/$DEV/hostsfile
+ sudo touch /var/lib/dnsmasq/$DEV/leases
+ sudo touch /var/lib/dnsmasq/$DEV/dnsmasq.conf
+ sudo sh -c "cat << 'EOF' >/var/lib/dnsmasq/$DEV/dnsmasq.conf
+except-interface=lo
+interface=$DEV
+bind-dynamic
+strict-order
+EOF"
+else
+ echo "Dnsmasq configured for $DEV"
+fi
+
+if [ ! -f "/etc/dnsmasq.d/$DEV.conf" ]; then
+ sudo mkdir -p /etc/dnsmasq.d/
+ sudo touch /etc/dnsmasq.d/$DEV.conf
+ sudo bash -c "echo "except-interface=$DEV" >> /etc/dnsmasq.d/$DEV.conf"
+ sudo bash -c "echo "bind-interfaces" >> /etc/dnsmasq.d/$DEV.conf"
+else
+ echo "Dnsmasq configured for $DEV"
+fi
+
+DNS_MASK_RUNNING=$(ps -ef | grep dnsmasq | grep -v "$0" | grep "$DEV")
+if [ "$DNS_MASK_RUNNING" == "" ]; then
+ sudo mkdir -p /var/run/dnsmasq/
+ sudo dnsmasq --conf-file=/var/lib/dnsmasq/$DEV/dnsmasq.conf
--pid-file=/var/run/dnsmasq/$DEV.pid
+else
+ echo "Dnsmasq running for $DEV"
+fi
diff --git a/scripts/setup_fc_networking.sh b/scripts/setup_fc_networking.sh
--- a/scripts/setup_fc_networking.sh
+++ b/scripts/setup_fc_networking.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+usage()
+{
+ cat <<-EOF
+usage: $0 <mode> <tap_device_name> (<tap_IP> <physical_NIC>) |
<bridge_name>
+sets up networking for Firecracker
+mode can be: 'bridged', 'natted' or 'clean' (restores IP tables and
deletes dnsmasq)
+EOF
+}
+
+if [ "$#" -lt 2 ]; then
+ usage
+ exit 1
+fi
+
+MODE=$1
+TAP_INTERFACE=$2
+TAP_IP=$3
+PHYSICAL_NIC=$4
+
+BRIDGE_NAME=$3
+
+THIS_DIR=$(dirname $0)
+
+#Create TAP device
+if [ "$MODE" == "bridged" ] && [ "$BRIDGE_NAME" != "" ]; then
+ $THIS_DIR/create_tap_device.sh "bridged" "$TAP_INTERFACE" "$BRIDGE_NAME"
+elif [ "$MODE" == "clean" ]; then
+ $THIS_DIR/remove_dnsmasq.sh "$TAP_INTERFACE"
+ $THIS_DIR/restore_iptables.sh
+elif [ "$MODE" == "natted" ]; then
+ if [ "$#" -lt 3 ]; then
+ usage
+ exit 1
+ fi
+ $THIS_DIR/create_tap_device.sh "natted" "$TAP_INTERFACE" "$TAP_IP"
+
+ if [ "$PHYSICAL_NIC" != "" ]; then
+ #Forwards traffic out of TAP device to the physical NIC
+ $THIS_DIR/setup_iptables.sh "$PHYSICAL_NIC" "$TAP_INTERFACE"
+
+ #Setup local DNS server
+ $THIS_DIR/setup_dnsmasq.sh "$TAP_INTERFACE"
+ echo "Set up IP forwarding $TAP_INTERFACE -> $PHYSICAL_NIC and light
DNS server for $TAP_INTERFACE"
+ else
+ echo "To make outgoing traffic work pass physical NIC name"
+ fi
+else
+ usage
+ exit 1
+fi
diff --git a/scripts/setup_iptables.sh b/scripts/setup_iptables.sh
--- a/scripts/setup_iptables.sh
+++ b/scripts/setup_iptables.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+if [ "$#" -ne 2 ]; then
+ echo "Usage: $0 <physical_NIC> <tap_NIC>"
+ echo "sets up forwarding from TAP device to physical NIC - wired or
wireless"
+ exit 1
+fi
+
+#Sets up forwarding for specified tap device and physical interface
+PHYSICAL_INTERFACE=$1
+TAP_DEVICE=$2
+
+sudo iptables-save > /tmp/osv_iptables.rules.old
+sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
+sudo iptables -t nat -A POSTROUTING -o $PHYSICAL_INTERFACE -j MASQUERADE
+sudo iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j
ACCEPT
+sudo iptables -A FORWARD -i $TAP_DEVICE -o $PHYSICAL_INTERFACE -j ACCEPT
+sudo iptables -A INPUT -i $TAP_DEVICE -p udp -m udp -m multiport --dports
53 -j ACCEPT
+sudo iptables -A INPUT -i $TAP_DEVICE -p tcp -m tcp -m multiport --dports
53 -j ACCEPT
Reply all
Reply to author
Forward
0 new messages