diff --git a/mosquitto/.gitignore b/mosquitto/.gitignore new file mode 100644 index 00000000..c504fa7f --- /dev/null +++ b/mosquitto/.gitignore @@ -0,0 +1,5 @@ +.config +.config.old +workdir/ +firecracker.socket +initrd.cpio diff --git a/mosquitto/Config.uk b/mosquitto/Config.uk new file mode 100644 index 00000000..c6a02755 --- /dev/null +++ b/mosquitto/Config.uk @@ -0,0 +1,48 @@ +# Configure Mosquitto application for a build that uses initrd to pass the root +# filesystem and bridge networking. + +config APPMOSQUITTO +bool "Configure Mosquitto MQTT broker with initrd as rootfs" +default y + + # Select application library (mosquitto). Use main function in application + # library. Other libraries, such as musl or lwip, are selected as + # dependencies of mosquitto. + select LIBMOSQUITTO + select LIBMOSQUITTO_MAIN_FUNCTION + + select LIBMUSL + + # networking stack + select LIBLWIP + select LIBLWIP_IPV4 + select LIBLWIP_TCP + select LIBLWIP_UDP + select LIBLWIP_DNS + select LIBLWIP_DHCP + select LIBLWIP_SOCKET + + # Select Filesystem core components and rootfs (initrd/cpio) + select LIBVFSCORE + select LIBVFSCORE_AUTOMOUNT_UP + select LIBRAMFS + select LIBUKCPIO + select LIBDEVFS + select LIBDEVFS_AUTOMOUNT + + # 9PFS + select LIBUK9P + select LIB9PFS + + # Use extended information (einfo) for configuring network parameters. + # This component parses the configuration string in the command line: + # netdev.ip=172.44.0.2/24:172.44.0.1::: + select LIBUKNETDEV_EINFO_LIBPARAM + + # Add support for environment variables. + select LIBPOSIX_ENVIRON_LIBPARAM + + # Allow passing random seed via command line + select LIBUKRANDOM_CMDLINE_SEED + select LIBUKRANDOM_DEVFS + select LIBUKRANDOM_GETRANDOM diff --git a/mosquitto/Makefile b/mosquitto/Makefile new file mode 100644 index 00000000..5caa9d87 --- /dev/null +++ b/mosquitto/Makefile @@ -0,0 +1,13 @@ +UK_ROOT ?= $(PWD)/workdir/unikraft +UK_BUILD ?= $(PWD)/workdir/build +UK_APP ?= $(PWD) +LIBS_BASE = $(PWD)/workdir/libs +UK_LIBS ?= $(LIBS_BASE)/musl:$(LIBS_BASE)/lwip:$(LIBS_BASE)/mosquitto + +.PHONY: all + +all: + @$(MAKE) -C $(UK_ROOT) L=$(UK_LIBS) A=$(UK_APP) O=$(UK_BUILD) + +$(MAKECMDGOALS): + @$(MAKE) -C $(UK_ROOT) L=$(UK_LIBS) A=$(UK_APP) O=$(UK_BUILD) $(MAKECMDGOALS) diff --git a/mosquitto/Makefile.uk b/mosquitto/Makefile.uk new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/mosquitto/Makefile.uk @@ -0,0 +1 @@ + diff --git a/mosquitto/README.md b/mosquitto/README.md new file mode 100644 index 00000000..4506031d --- /dev/null +++ b/mosquitto/README.md @@ -0,0 +1,253 @@ +# Mosquitto MQTT Broker on Unikraft + +Build and run the Mosquitto MQTT broker on Unikraft. +Follow the instructions below to set up, configure, build and run Mosquitto. +Make sure you installed the [requirements](../README.md#requirements). + +## Quick Setup (aka TLDR) + +For a quick setup, run the commands below. +Note that you still need to install the [requirements](../README.md#requirements). +Before everything, make sure you run the [top-level `setup.sh` script](../setup.sh). + +**Note**: This is a network application. +For using QEMU, enable bridged networking, as instructed in the [top-level `README.md`](../README.md#qemu): + +```console +echo "allow all" | sudo tee /etc/qemu/bridge.conf +``` + +To build and run the application for `x86_64`, use the commands below: + +```console +./setup.sh +make distclean +wget -O /tmp/defconfig https://raw.githubusercontent.com/unikraft/catalog-core/refs/heads/scripts/mosquitto/scripts/defconfig/qemu.x86_64 +UK_DEFCONFIG=/tmp/defconfig make defconfig +``` + +```console +make -j $(nproc) +sudo ip link set dev virbr0 down +sudo ip link del dev virbr0 +sudo ip link add dev virbr0 type bridge +sudo ip address add 172.44.0.1/24 dev virbr0 +sudo ip link set dev virbr0 up + +# Create the initial ramdisk (initrd) containing the mosquitto config +rm -f initrd.cpio +cd rootfs && find . | cpio -o -H newc > ../initrd.cpio && cd .. + +sudo qemu-system-x86_64 \ + -nographic \ + -m 16 \ + -cpu max \ + -netdev bridge,id=en0,br=virbr0 -device virtio-net-pci,netdev=en0 \ + -append "mosquitto netdev.ip=172.44.0.2/24:172.44.0.1::: vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] random.seed=12213123 -- -c /etc/mosquitto/mosquitto.conf" \ + -kernel workdir/build/mosquitto_qemu-x86_64 \ + -initrd ./initrd.cpio +``` + +This will configure, build and run Mosquitto on Unikraft. +You can see how to test it in the ["Test" section](#test). + +## Set Up + +Set up the required repositories. +For this, you have two options: + +1. Use the `setup.sh` script: + + ```console + ./setup.sh + ``` + + It will create symbolic links to the required repositories in `../repos/`. + Be sure to run the [top-level `setup.sh` script](../setup.sh). + +2. Have your custom setup of repositories in the `workdir/` directory. + Clone, update and customize repositories to your own needs. + +## Clean + +While not strictly required, it is safest to clean the previous build artifacts: + +```console +make distclean +``` + +## Configure + +To configure the kernel, use: + +```console +wget -O /tmp/defconfig https://raw.githubusercontent.com/unikraft/catalog-core/refs/heads/scripts/mosquitto/scripts/defconfig/qemu.x86_64 +UK_DEFCONFIG=/tmp/defconfig make defconfig +``` + +If you wish to change the configuration further, you can use: + +```console +make menuconfig +``` + +The end result will be the creation of the `.config` configuration file. + +## Build + +Build the application for the current configuration: + +```console +make -j $(nproc) +``` + +This results in the creation of the `workdir/build/` directory storing the build artifacts. + +### Build the Filesystem + +The filesystem is to be packed into `initrd.cpio`, an initial ramdisk CPIO file. +Use the command below for that: + +```console +cd rootfs && find . | cpio -o -H newc > ../initrd.cpio && cd .. +``` + +## Run + +Run the resulting image using the corresponding platform tool. +Firecracker requires KVM support. +Xen requires a system with Xen installed. + +A successful run will show a message such as the one below: + +```text +Booting from ROM..[ 0.000000] ERR: [libukallocbbuddy] 11000: Failed to add memory rs +en1: Added +en1: Interface is up +Powered by +o. .o _ _ __ _ +Oo Oo ___ (_) | __ __ __ _ ' _) :_ +oO oO ' _ `| | |/ / _)' _` | |_| _) +oOo oOO| | | | | (| | | (_) | _) :_ + OoOoO ._, ._:_:_,\_._, .__,_:_, \___) + Kiviuq 0.20.0~f5090fa7 +1773527810: Info: running mosquitto as user id: -38. +1773527810: mosquitto version 2.1.2 starting +1773527810: Config loaded from /etc/mosquitto/mosquitto.conf. +1773527810: Bridge support available. +1773527810: Persistence support available. +1773527810: TLS support NOT available. +1773527810: TLS-PSK support NOT available. +1773527810: Websockets support NOT available. +1773527810: Opening ipv6 listen socket on port 1883. +1773527810: Opening ipv4 listen socket on port 1883. +1773527810: mosquitto version 2.1.2 running +``` + +> [!NOTE] +> The error "ERR: [libukallocbbuddy] 11000: Failed to add memory region" during boot is completely normal and harmless. It simply means memory allocator tried to register a specific memory region from the BIOS that was too small or overlapping, but it still successfully registers the main RAM directly afterwards. + +### Run on QEMU/x86_64 + +To set up networking, use the commands below: + +```console +sudo ip link set dev virbr0 down +sudo ip link del dev virbr0 +sudo ip link add dev virbr0 type bridge +sudo ip address add 172.44.0.1/24 dev virbr0 +sudo ip link set dev virbr0 up +``` + +Now run the Unikraft image: + +```console +sudo qemu-system-x86_64 \ + -nographic \ + -m 16 \ + -cpu max \ + -netdev bridge,id=en0,br=virbr0 -device virtio-net-pci,netdev=en0 \ + -append "mosquitto netdev.ip=172.44.0.2/24:172.44.0.1::: vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] random.seed=12213123 -- -c /etc/mosquitto/mosquitto.conf" \ + -kernel workdir/build/mosquitto_qemu-x86_64 \ + -initrd ./initrd.cpio +``` + +### Run on Firecracker/x86_64 + +To set up networking, use the commands below: + +```console +sudo ip link set dev virbr0 down +sudo ip link del dev virbr0 +sudo ip link set dev tap0 down +sudo ip link del dev tap0 +sudo ip tuntap add dev tap0 mode tap +sudo ip address add 172.44.0.1/24 dev tap0 +sudo ip link set dev tap0 up +``` + +Now run the Unikraft image: + +```console +rm -f firecracker.socket +sudo firecracker-x86_64 --config-file fc.x86_64.json --api-sock firecracker.socket +``` + +### Run on Xen/x86_64 + +To set up networking, use the commands below: + +```console +sudo ip link set dev virbr0 down +sudo ip link del dev virbr0 +sudo ip link set dev tap0 down +sudo ip link del dev tap0 +sudo ip link add dev virbr0 type bridge +sudo ip address add 172.44.0.1/24 dev virbr0 +sudo ip link set dev virbr0 up +``` + +Now run the Unikraft image: + +```console +sudo xl create -c xen.x86_64.cfg +``` + +## Test + +To test Mosquitto on Unikraft, open two terminals on your host machine. + +In terminal 1 (subscribe): +```console +mosquitto_sub -h 172.44.0.2 -p 1883 -t "test/unikraft" +``` + +In terminal 2 (publish): +```console +mosquitto_pub -h 172.44.0.2 -p 1883 -t "test/unikraft" -m "Hello from Mosquitto on Unikraft!" +``` + +In terminal 1, you should see: +```text +Hello from Mosquitto on Unikraft! +``` + +## Clean Up + +In order to remove the build artifacts, use: + +```console +make clean +``` + +In order to remove fetched files also, that is the removal of the `workdir/build/` directory, use: + +```console +make properclean +``` + +In order to remove the generated `.config` file as well, use: + +```console +make distclean +``` diff --git a/mosquitto/fc.arm64.json b/mosquitto/fc.arm64.json new file mode 100644 index 00000000..982e493f --- /dev/null +++ b/mosquitto/fc.arm64.json @@ -0,0 +1,21 @@ +{ + "boot-source": { + "kernel_image_path": "workdir/build/mosquitto_fc-arm64", + "boot_args": "mosquitto_fc-arm64 netdev.ip=172.44.0.2/24:172.44.0.1::: vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] random.seed=12213123 -- -c /etc/mosquitto/mosquitto.conf", + "initrd_path": "initrd.cpio" + }, + "drives": [], + "machine-config": { + "vcpu_count": 1, + "mem_size_mib": 16, + "smt": false, + "track_dirty_pages": false + }, + "network-interfaces": [ + { + "iface_id": "net1", + "guest_mac": "06:00:ac:10:00:02", + "host_dev_name": "tap0" + } + ] +} diff --git a/mosquitto/fc.x86_64.json b/mosquitto/fc.x86_64.json new file mode 100644 index 00000000..bd0fd4bf --- /dev/null +++ b/mosquitto/fc.x86_64.json @@ -0,0 +1,21 @@ +{ + "boot-source": { + "kernel_image_path": "workdir/build/mosquitto_fc-x86_64", + "boot_args": "mosquitto_fc-x86_64 netdev.ip=172.44.0.2/24:172.44.0.1::: vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] random.seed=12213123 -- -c /etc/mosquitto/mosquitto.conf", + "initrd_path": "initrd.cpio" + }, + "drives": [], + "machine-config": { + "vcpu_count": 1, + "mem_size_mib": 16, + "smt": false, + "track_dirty_pages": false + }, + "network-interfaces": [ + { + "iface_id": "net1", + "guest_mac": "06:00:ac:10:00:02", + "host_dev_name": "tap0" + } + ] +} diff --git a/mosquitto/rootfs/etc/mosquitto/mosquitto.conf b/mosquitto/rootfs/etc/mosquitto/mosquitto.conf new file mode 100644 index 00000000..f277f632 --- /dev/null +++ b/mosquitto/rootfs/etc/mosquitto/mosquitto.conf @@ -0,0 +1,7 @@ +listener 1883 +allow_anonymous true +log_dest stdout +persistence true +persistence_location /data/ +autosave_interval 1 +autosave_on_changes true diff --git a/mosquitto/scripts/defconfig/qemu.arm64 b/mosquitto/scripts/defconfig/qemu.arm64 new file mode 100644 index 00000000..6a024e44 --- /dev/null +++ b/mosquitto/scripts/defconfig/qemu.arm64 @@ -0,0 +1,31 @@ +CONFIG_ARCH_ARM_64=y +CONFIG_PLAT_KVM=y +CONFIG_KVM_VMM_QEMU=y +CONFIG_LIBUKPLAT_NATIVE_PAL=y +CONFIG_VIRTIO_DEVICE=y +CONFIG_HAVE_PCI=y +CONFIG_LIBUKBUS_PCI=y +CONFIG_LIBVIRTIO_9P=y +CONFIG_LIBVIRTIO_BUS=y +CONFIG_LIBVIRTIO_NET=y +CONFIG_LIBVIRTIO_PCI=y +CONFIG_LIBVIRTIO_RING=y +CONFIG_LIB9PFS=y +CONFIG_LIBDEVFS=y +CONFIG_LIBDEVFS_AUTOMOUNT=y +CONFIG_LIBPOSIX_EVENT=y +CONFIG_LIBMUSL=y +CONFIG_LIBLWIP=y +CONFIG_LWIP_UKNETDEV=y +CONFIG_LWIP_AUTOIFACE=y +CONFIG_LWIP_THREADS=y +CONFIG_LWIP_IPV4=y +CONFIG_LWIP_IPV6=y +CONFIG_LWIP_UDP=y +CONFIG_LWIP_TCP=y +CONFIG_LWIP_DNS=y +CONFIG_LWIP_SOCKET=y +CONFIG_LIBMOSQUITTO=y +CONFIG_LIBMOSQUITTO_MAIN_FUNCTION=y +CONFIG_APPMOSQUITTO=y +CONFIG_LIBVFSCORE_AUTOMOUNT_CI_INITRD=y diff --git a/mosquitto/scripts/defconfig/qemu.x86_64 b/mosquitto/scripts/defconfig/qemu.x86_64 new file mode 100644 index 00000000..bc0681d6 --- /dev/null +++ b/mosquitto/scripts/defconfig/qemu.x86_64 @@ -0,0 +1,6 @@ +CONFIG_PLAT_KVM=y +CONFIG_LIBVFSCORE_AUTOMOUNT_CI=y +CONFIG_LIBVFSCORE_AUTOMOUNT_CI_INITRD=y +CONFIG_LWIP_IPV6=y +CONFIG_ARCH_X86_64=y +CONFIG_UK_NAME="mosquitto" diff --git a/mosquitto/setup.sh b/mosquitto/setup.sh new file mode 100755 index 00000000..f1b39223 --- /dev/null +++ b/mosquitto/setup.sh @@ -0,0 +1,35 @@ +#!/bin/sh + +check_exists_and_create_symlink() +{ + path="$1" + + if ! test -d workdir/"$path"; then + if ! test -d ../repos/"$path"; then + echo "No directory ../repos/$path. Run the top-level setup.sh script first." 1>&2 + exit 1 + fi + depth=$(echo "$path" | awk -F / '{ print NF }') + if test "$depth" -eq 1; then + ln -sfn ../../repos/"$path" workdir/"$path" + elif test "$depth" -eq 2; then + ln -sfn ../../../repos/"$path" workdir/"$path" + else + echo "Unknown depth of path $path." 1>&2 + exit 1 + fi + fi +} + +if ! test -d workdir; then + mkdir workdir +fi + +if ! test -d workdir/libs; then + mkdir workdir/libs +fi + +check_exists_and_create_symlink "unikraft" +check_exists_and_create_symlink "libs/musl" +check_exists_and_create_symlink "libs/lwip" +check_exists_and_create_symlink "libs/mosquitto" diff --git a/mosquitto/xen.arm64.cfg b/mosquitto/xen.arm64.cfg new file mode 100644 index 00000000..10c75872 --- /dev/null +++ b/mosquitto/xen.arm64.cfg @@ -0,0 +1,8 @@ +name = "mosquitto" +vcpus = "1" +kernel = "./workdir/build/mosquitto_xen-arm64" +ramdisk = "./initrd.cpio" +cmdline = "mosquitto_xen-arm64 netdev.ip=172.44.0.2/24:172.44.0.1::: vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] random.seed=12213123 -- -c /etc/mosquitto/mosquitto.conf" +vif = ['bridge=virbr0'] +memory = "16" +type = "pvh" diff --git a/mosquitto/xen.x86_64.cfg b/mosquitto/xen.x86_64.cfg new file mode 100644 index 00000000..b3f1affe --- /dev/null +++ b/mosquitto/xen.x86_64.cfg @@ -0,0 +1,8 @@ +name = "mosquitto" +vcpus = "1" +kernel = "./workdir/build/mosquitto_xen-x86_64" +ramdisk = "./initrd.cpio" +cmdline = "mosquitto_xen-x86_64 netdev.ip=172.44.0.2/24:172.44.0.1::: vfs.fstab=[ \"initrd0:/:extract::ramfs=1:\" ] random.seed=12213123 -- -c /etc/mosquitto/mosquitto.conf" +vif = ['bridge=virbr0'] +memory = "16" +type = "pv" diff --git a/setup.sh b/setup.sh index 451b924d..9daf6fd8 100755 --- a/setup.sh +++ b/setup.sh @@ -15,3 +15,4 @@ test -d repos/apps/elfloader || git clone https://github.com/unikraft/app-elfloa test -d repos/libs/redis || git clone https://github.com/unikraft/lib-redis repos/libs/redis test -d repos/libs/wamr || git clone https://github.com/unikraft/lib-wamr repos/libs/wamr test -d repos/libs/sqlite || git clone https://github.com/unikraft/lib-sqlite repos/libs/sqlite +test -d repos/libs/mosquitto || git clone https://github.com/unikraft/lib-mosquitto repos/libs/mosquitto