OpenWrt Core Component: ubus (2): Source Code Structure

<span><span>ubus</span></span> is designed with a concept similar to <span><span>d-bus</span></span> in Linux desktop systems, providing system-level bus functionality. However, compared to <span><span>d-bus</span></span>, it reduces memory usage, making it suitable for the extreme operating environments of low-performance CPUs and low memory in embedded systems.

The core component is the <span><span>ubusd</span></span> daemon, which provides an interface for other daemons to register themselves and send messages. It offers a bus layer that runs in the background during system startup, responsible for message routing and delivery between processes.

As one of the core components of OpenWrt, I plan to introduce ubus in a series of articles. Please refer to related articles:

OpenWrt Core Component: ubus (1): Command Line Tool

This article will introduce the source code structure of the ubus project.Software package source path As a system component of <span><span>OpenWrt</span></span>, ubus is compiled by default, so you just need to search in the root directory of your compiled system source:

ruok@ruok-vm:~/Downloads/openwrt-24.10.0$ find . -name ubus
./build_dir/target-aarch64_cortex-a53_musl/root-mediatek/bin/ubus
./build_dir/target-aarch64_cortex-a53_musl/root.orig-mediatek/bin/ubus
./build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce/ipkg-install/usr/bin/ubus
./build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce/.pkgdir/ubus
./build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce/.pkgdir/ubus/bin/ubus
./build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce/ubus
./build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce/ipkg-aarch64_cortex-a53/ubus
./build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce/ipkg-aarch64_cortex-a53/ubus/bin/ubus
./build_dir/target-aarch64_cortex-a53_musl/firewall4-2024.12.18~18fc0ead/tests/mocks/ubus
./package/system/ubus
./staging_dir/target-aarch64_cortex-a53_musl/root-mediatek/bin/ubus
./staging_dir/target-aarch64_cortex-a53_musl/usr/bin/ubus

From this, we can see that the source path for <span><span>ubus</span></span> is:<span><span>package/system/ubus</span></span>.

However, this path only contains a <span><span>Makefile</span></span> file:

ruok@ruok-vm:~/Downloads/openwrt-24.10.0/package/system/ubus$ ll
total 12
drwxrwxr-x  2 ruok ruok 4096 Feb  4 07:10 ./
drwxrwxr-x 23 ruok ruok 4096 Feb  4 07:10 ../
-rw-rw-r--  1 ruok ruok 1937 Feb  4 07:10 Makefile

The top-level Makefile

Those familiar with the OpenWrt package structure should know that a software package has two layers of Makefiles. Let’s first look at the content of this top-level <span><span>Makefile</span></span> file:

include $(TOPDIR)/rules.mk
PKG_NAME:=ubus
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/ubus.git
PKG_SOURCE_DATE:=2025-01-02
PKG_SOURCE_VERSION:=afa57cce0aff82f4a7a0e509d4387ebc23dd3be7
PKG_MIRROR_HASH:=a0b3c1961f5f49d31c34a44576ce44538c3ee97bfce97f86f732d7ecc1df9798
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
CMAKE_INSTALL:=1
PKG_LICENSE:=LGPL-2.1
PKG_LICENSE_FILES:=
PKG_MAINTAINER:=Felix Fietkau <[email protected]>
PKG_BUILD_FLAGS:=lto
PKG_ASLR_PIE_REGULAR:=1
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk

define Package/ubus
  SECTION:=base
  CATEGORY:=Base system
  DEPENDS:=+libubus +libblobmsg-json +ubusd
  TITLE:=OpenWrt RPC client utility
endef

define Package/ubusd
  SECTION:=base
  CATEGORY:=Base system
  TITLE:=OpenWrt RPC daemon
  DEPENDS:=+libubox +libblobmsg-json
  USERID:=ubus=81:ubus=81
endef

define Package/libubus
  SECTION:=libs
  CATEGORY:=Libraries
  DEPENDS:=+libubox
  ABI_VERSION:=$(PKG_ABI_VERSION)
  TITLE:=OpenWrt RPC client library
endef

define Package/libubus-lua
  SECTION:=libs
  CATEGORY:=Libraries
  DEPENDS:=+libubus +liblua
  TITLE:=Lua binding for the OpenWrt RPC client
endef

TARGET_CFLAGS += -I$(STAGING_DIR)/usr/include
CMAKE_OPTIONS += \
  -DLUAPATH=/usr/lib/lua \
  -DABIVERSION="$(PKG_ABI_VERSION)"

define Package/ubus/install
  $(INSTALL_DIR) $(1)/bin
  $(CP) $(PKG_INSTALL_DIR)/usr/bin/ubus $(1)/bin
endef

define Package/ubusd/install
  $(INSTALL_DIR) $(1)/sbin
  $(CP) $(PKG_INSTALL_DIR)/usr/sbin/ubusd $(1)/sbin
endef

define Package/libubus/install
  $(INSTALL_DIR) $(1)/lib
  $(CP) $(PKG_INSTALL_DIR)/usr/lib/libubus.so.* $(1)/lib
endef

define Package/libubus-lua/install
  $(INSTALL_DIR) $(1)/usr/lib/lua
  $(CP) $(PKG_BUILD_DIR)/lua/ubus.so $(1)/usr/lib/lua
endef

$(eval $(call BuildPackage,libubus))
$(eval $(call BuildPackage,libubus-lua))
$(eval $(call BuildPackage,ubus))
$(eval $(call BuildPackage,ubusd))

At the beginning, it describes the code repository path and version number for <span><span>ubus</span></span>. In fact, the code will be downloaded to the <span><span>dl</span></span> directory:

ruok@ruok-vm:~/Downloads/openwrt-24.10.0$ ls dl/ | grep ubus
ubus-2025.01.02~afa57cce.tar.zst

To clarify, the *.tar.zst is just a compressed package format, which has the advantages of fast compression and high efficiency. It will become more common in the future. If you want to learn about its usage, you can refer to the article:

What is tar.zst in OpenWrt 24.10

Next, this <span><span>Makefile</span></span> defines four software packages:

  • <span><span>ubus</span></span>

  • <span><span>ubusd</span></span>

  • <span><span>libubus</span></span>

  • <span><span>libubus-lua</span></span>

Finally, it declares the compilation order of the four software packages defined earlier:

$(eval $(call BuildPackage,libubus))
$(eval $(call BuildPackage,libubus-lua))
$(eval $(call BuildPackage,ubus))
$(eval $(call BuildPackage,ubusd))

Note that because these packages have dependencies, the order must be correct.

Ultimately, four important deliverables will be generated, as can be seen in the <span><span>Makefile</span></span> install script:

  • <span><span>ubus</span></span>: This is a command-line tool that interacts with the daemon <span><span>ubusd</span></span>, which can be used for configuration and debugging, as well as for scripting.

  • <span><span>ubusd</span></span>: The daemon, which is the core implementation of the <span><span>ubus</span></span> bus.

  • <span><span>libubus.so</span></span>: A unified <span><span>ubus API</span></span> interface library, which allows other processes to quickly integrate <span><span>ubus</span></span> services.

  • <span><span>ubus.so</span></span>: An API interface library provided for Lua programs.

The implementation source code path The previous section introduced the package path corresponding to ubus, while its C code implementation requires extracting the aforementioned .tar.zst compressed package, where almost all core code can be found at the same directory level:

ruok@ruok-vm:~/Downloads/openwrt-24.10.0/build_dir/target-aarch64_cortex-a53_musl/ubus-2025.01.02~afa57cce$ ls
build.ninja          install_manifest.txt     libubus-internal.h   lua            ubusd.c          ubusd_obj.c
cli.c                ipkg-aarch64_cortex-a53  libubus-io.c         tests          ubusd_event.c    ubusd_obj.h
CMakeCache.txt       ipkg-install             libubus-obj.c        ubus           ubusd.h          ubusd_proto.c
CMakeFiles           libubus-acl.c            libubus-req.c        ubus_common.h  ubusd_id.c       ubusmsg.h
cmake_install.cmake  libubus.c                libubus.so           ubusd          ubusd_id.h      ubusd_proto.c
CMakeLists.txt       libubusd_library.a       libubus.so.20250102  ubusd_acl.c    ubusd_main.c
examples             libubus.h                libubus-sub.c        ubusd_acl.h    ubusd_monitor.c

This part of the source code uses <span><span>cmake</span></span> to control the compilation.Source code compilation You can compile the components in the <span><span>ubus</span></span> package separately by executing the following command:

ruok@ruok-vm:~/Downloads/openwrt-24.10.0$ make package/system/ubus/{clean,prepare,compile} V=s

Leave a Comment