From: Waldemar Kozaczuk <[email protected]>
Committer: Waldemar Kozaczuk <[email protected]>
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 <[email protected]>
Signed-off-by: Waldemar Kozaczuk <[email protected]>

---
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

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000bcfb0005965dbbf3%40google.com.

Reply via email to