Skip to content

Commit

Permalink
Refactor and enhance firecracker script
Browse files Browse the repository at this point in the history
This patch:
- refactors firecracker.py to better handle error scenarios
- adds ability to use external networking bridge through -b parameter (see scripts/setup-external-bridge.sh)
- adds ability to specify custom location of kernel and image files

Signed-off-by: Waldemar Kozaczuk <[email protected]>
  • Loading branch information
wkozaczuk committed Mar 25, 2019
1 parent e36de53 commit 053e0a4
Showing 1 changed file with 46 additions and 18 deletions.
64 changes: 46 additions & 18 deletions scripts/firecracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,29 @@ def print_time(msg):
print("%s: %s" % (now.isoformat(), msg))


def setup_tap_interface(tap_interface_name, tap_ip):
def setup_tap_interface(tap_interface_name, tap_ip, bridge_name):
# Setup tun tap interface if does not exist
tuntap_interfaces = subprocess.check_output(["ip", 'tuntap'])
# 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)
print("The tap interface %s not found -> needs to set it up!" % tap_interface_name)
# Check if the bridge exists if user specified it
if 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', '-w', 'net.ipv4.conf.%s.proxy_arp=1' % tap_interface_name])
subprocess.call(['sudo', 'sysctl', '-w', 'net.ipv6.conf.%s.disable_ipv6=1' % tap_interface_name])
subprocess.call(['sudo', 'ip', 'addr', 'add', '%s/30' % tap_ip, 'dev', tap_interface_name])
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])
else:
subprocess.call(['sudo', 'ip', 'addr', 'add', '%s/30' % tap_ip, 'dev', tap_interface_name])


def find_firecracker(dirname):
firecracker_path = os.path.join(dirname, '../.firecracker/firecracker')
Expand Down Expand Up @@ -148,9 +160,9 @@ def find_firecracker(dirname):
return firecracker_path


def disk_path(dirname):
qcow_disk_path = os.path.join(dirname, '../build/release/usr.img')
raw_disk_path = os.path.join(dirname, '../build/release/usr.raw')
def disk_path(qcow_disk_path):
dot_pos = qcow_disk_path.rfind('.')
raw_disk_path = qcow_disk_path[0:dot_pos] + '.raw'

# Firecracker is not able to use disk image files in QCOW format
# so we have to convert usr.img to raw format if the raw disk is missing
Expand Down Expand Up @@ -196,13 +208,30 @@ def main(options):
firecracker = start_firecracker(firecracker_path, socket_path)

# Prepare arguments we are going to pass when creating VM instance
kernel_path = os.path.join(dirname, '../build/release/loader-stripped.elf')
raw_disk_path = disk_path(dirname)
kernel_path = options.kernel
if not kernel_path:
kernel_path = os.path.join(dirname, '../build/release/loader-stripped.elf')

qemu_disk_path = options.image
if not qemu_disk_path:
qemu_disk_path = os.path.join(dirname, '../build/release/usr.img')
raw_disk_path = disk_path(qemu_disk_path)

cmdline = options.execute
if not cmdline:
with open(os.path.join(dirname, '../build/release/cmdline'), 'r') as f:
cmdline = f.read()
cmdline = "--nopci %s" % cmdline

if options.networking:
tap_ip = '172.16.0.1'
setup_tap_interface('fc_tap0', tap_ip, options.bridge)
if not options.bridge:
client_ip = '172.16.0.2'
cmdline = '--ip=eth0,%s,255.255.255.252 --defaultgw=%s %s' % (client_ip, tap_ip, cmdline)

if options.verbose:
cmdline = '--verbose ' + cmdline

# Create API client and make API calls
client = ApiClient(socket_path.replace("/", "%2F"))
Expand All @@ -223,15 +252,8 @@ def main(options):
client.add_disk(raw_disk_path)
print_time("Added disk")

cmdline = "--nopci %s" % cmdline
if options.networking:
tap_ip = '172.16.0.1'
setup_tap_interface('fc_tap0', tap_ip)
client.add_network_interface('eth0', 'fc_tap0')
client_ip = '172.16.0.2'
cmdline = '--ip=eth0,%s,255.255.255.252 --defaultgw=%s %s' % (client_ip, tap_ip, cmdline)
if options.verbose:
cmdline = '--verbose ' + cmdline

client.create_instance(kernel_path, cmdline)
print_time("Created OSv VM with cmdline: %s" % cmdline)
Expand Down Expand Up @@ -263,8 +285,14 @@ def main(options):
help="specify memory: ex. 1G, 2G, ...")
parser.add_argument("-e", "--execute", action="store", default=None, metavar="CMD",
help="overwrite command line")
parser.add_argument("-i", "--image", action="store", default=None, metavar="CMD",
help="path to disk image file. defaults to ../build/release/usr.img")
parser.add_argument("-k", "--kernel", action="store", default=None, metavar="CMD",
help="path to kernel loader file. defaults to ../build/release/loader-stripped.elf")
parser.add_argument("-n", "--networking", action="store_true",
help="needs root to setup tap networking first time")
parser.add_argument("-b", "--bridge", action="store", default=None,
help="bridge name for tap networking")
parser.add_argument("-V", "--verbose", action="store_true",
help="pass --verbose to OSv, to display more debugging information on the console")

Expand Down

0 comments on commit 053e0a4

Please sign in to comment.