---
title: OpenWRT UBUS
tags:
description: View the slide with "Slide Mode".
---
# OpenWrt UBUS
## What is UBUS?
Ubus is an RPC tool of OpenWRT, a micro system bus architecture. The aim of Ubus is to provide system-level Inter-process Communication(IPC) for various background processes and applications. Ubus is basically consistent with D-Bus in the design conception, providing system-level bus function. In order to be compatible with constrained environment says embedded systems, ubus reduced memory footprint.
- Provide various daemons and applications with IPC(Inter-process Communication) service.
- Work as a broker, forward messages between related application(s) in different ways.
- Several tools are invented for accessing UBUS
- libubus: a library for software to access UBUS.
- Cmd-line ubus tool.
- Ubus Lua module
---
### IPC
Inter-process Communication refers to mechanism allowing processes to manage shared data. There are different approaches to IPC tailored to different software requirements, says performance, modularity, network bandwidth and latency.
Examples of IPC method:
- File
- Signal
- Socket / Unix domain Socket
- Shared memory
Most of IPC methods use client-server model to share data between processes.
### Connection model of client-server model
```graphviz
digraph {
compound=true
rankdir=LR
graph [ fontname="Source Sans Pro", fontsize=20 ];
node [ fontname="Source Sans Pro", fontsize=18];
edge [ fontname="Source Sans Pro", fontsize=12 ];
subgraph cluster2 {
concentrate=true
s1 [label="Process 1"] [shape=box]
s2 [label="Process 2"] [shape=box]
d [label="Process 3"] [shape=box]
e [label="Process 4"] [shape=box]
f [label="Process 5"] [shape=box]
g [label="Process 6"] [shape=box]
#sync [label="File, Shared Memory,\nSocket, Signal" shape=plaintext ]
s1 -> d
d -> s1
e -> s1
s1 -> e
f -> s1
s1 -> f
e -> s2
s2 -> e
f -> s2
s2 -> f
s2 -> g
g -> s2
s1 -> s2
s2 -> s1
d -> e
e -> d
f -> d
d -> f
label="Client-server Model(m:n)"
}
subgraph cluster1 {
concentrate = true
a [label="Process 1\nServer"] [shape=box]
b [label="Process 2\nClient"] [shape=box]
#sync [label="File, Shared Memory,\nSocket, Signal" shape=plaintext ]
b -> a [dir="left"] [label="Request"]
a -> b [dir="right"] [label="Response"]
label="Client-server Model(1:1)"
}
}
```
While there are m servers, and each server has $$ n_k $$ clients. The number of IPC connections in client/server model is:
$$
\sum_{k=1}^{m}n_k
$$
### Connection model of UBUS
Ubus uses the broker pattern as its architecture. There are three components to perform IPC through ubus.
1. **ubus daemon**: Broker/middleman between ubus server object and ubus client object, manages registration, and forwards messages between server and client object.
2. **ubus server object**: Usually interface/daemon of some software. Registers to ubus daemon with methods provided for client. Server objects and the methods registered can be looked up and called by client objects.
3. **ubus client object**: Caller of server objects and methods.
```graphviz
digraph {
compound=true
rankdir=UD
graph [ fontname="Source Sans Pro", fontsize=20 ];
node [ fontname="Source Sans Pro", fontsize=18];
edge [ fontname="Source Sans Pro", fontsize=12 ];
subgraph ubus {
label = "Ubus model"
concentrate = true
ubus [label = " Ubusd "] [shape=box]
p1 [label = "Process 1\nServer Object"] [shape=box]
p2 [label = "Process 2\nServer Object"] [shape=box]
p3 [label = "Process 3\nClient Object"] [shape=box]
p4 [label = "Process 4\nClient Object"] [shape=box]
p5 [label = "Process 5\nClient Object"] [shape=box]
p6 [label = "Process 6\nClient Object"] [shape=box]
p1 -> ubus
ubus -> p1
p2 -> ubus
ubus -> p2
p3 -> ubus
ubus -> p3
p4 -> ubus
ubus -> p4
p5 -> ubus
ubus -> p5
p6 -> ubus
ubus -> p6
}
}
```
In this architecture, the number of connections is the number of processes, including both service "clients" and "servers", which is much less than IPC implementations under client/server model.
:cat:
### Roles in UBUS
There are different roles in Ubus IPC processes.
1. Object
- Process registered to ubusd, including service and service callers.
2. Method
- Procedure provdied by objects. Object can provide various methods as a server.
3. Data
- Information in JSON format carried by requests or replies.
![](https://i.imgur.com/K0h3BYJ.png)
Relations of object, method and data under UBUS.
![](https://i.imgur.com/GhGSIpQ.png)
List of object on Ubus, methods and related data signature of 'system'.
4. Subscriber
- Object subscribed to target service object. Subscribers will be notified once target service object sends a notification to ubusd.
5. Event
- Event in Ubus is identified by a string called "event pattern". Event can be registered by object. Object can send data to ubusd with event pattern.
6. Event Registrant
- Object registered to event with "event pattern". Ubusd forwards data to event registrant once message with matched "event pattern" is received.
### Data format of UBUS - JSON
Ubus uses JSON as data format to call object, method and respond to request.
[https://www.json.org/json-en.html](https://www.json.org/json-en.html)
Here is an status example in JSON format. We call the method `status` of object `network.interface.wan3` with null message `'{}'`.
```json=0
root@ugwcpe:/# ubus call network.interface.wan3 status
{
"up": true,
"pending": false,
"available": true,
"autostart": true,
"dynamic": false,
"uptime": 5,
"l3_device": "eth1_wan3",
"proto": "dhcp",
"device": "eth1_wan3",
"updated": [
"addresses",
"routes",
"data"
],
"metric": 0,
"dns_metric": 0,
"delegation": true,
"ipv4-address": [
{
"address": "192.168.121.101",
"mask": 24
}
],
"ipv6-address": [
],
"ipv6-prefix": [
],
"ipv6-prefix-assignment": [
],
"route": [
{
"target": "0.0.0.0",
"mask": 0,
"nexthop": "192.168.121.1",
"source": "192.168.121.101/32"
}
],
"dns-server": [
"192.168.121.1",
"8.8.8.8"
],
"dns-search": [
"gemteks.com"
],
"inactive": {
"ipv4-address": [
],
"ipv6-address": [
],
"route": [
],
"dns-server": [
],
"dns-search": [
]
},
"data": {
"leasetime": 86400
}
}
```
### Approaches of data flow
There are three delivery schemes to implement IPC in Ubus.
1. One-to-one
- Post data or requests to specific object.
![](https://i.imgur.com/sxSHRIc.png)
2. One-to-many(group by object)
- Post data to multiple subscribers that subscribed to this object.
![](https://i.imgur.com/r7wK89y.png)
3. One-to-many(group by event)
- Post data to multiple listeners of same event pattern.
![](https://i.imgur.com/s359hus.png)
---
## Data flow sequence of UBUS
As mentioned, There are three delivery schemes to implement IPC in Ubus
1. Invoke
- Post data directly to one object with object ID.
2. Subscribe/Notify
- Post data to multiple subscribers that subscribed to same object.
3. Event boardcast
- Post data to multiple listeners of same event pattern.
### 1. Invoke
Data flow of invoke.
0. Startup of UBUSD.
1. Connection establishment of Process 1.
2. Registration of Process 1 object with provided method.
3. Connection establishment of Process 2.
4. **Object id lookup.**
5. **Request with object id, method, and required data(msg).**
6. Deregistration of object.
Syntax:
---> :Client to Ubusd
-- ->:Ubusd to Client
```sequence
UBUSD->UBUSD:0: create socket bind listen
UBUS CLIENT 1\nProcess 1->UBUSD:1.1: Connect
UBUSD-->UBUS CLIENT 1\nProcess 1:1.2: Accept
UBUSD-->UBUS CLIENT 1\nProcess 1:1.3: Hello
UBUS CLIENT 1\nProcess 1->UBUSD:2.1: Regist object, method
UBUSD->UBUSD:2.2: Update Avl-tree
Note right of UBUSD:Assign and add objpath, \nobjid, objtype, \nmethod to avl-tree.
UBUS CLIENT 2\nProcess 2->UBUSD:3.1: Connect
UBUSD-->UBUS CLIENT 2\nProcess 2:3.2: Accept
UBUSD-->UBUS CLIENT 2\nProcess 2:3.3: Hello
UBUS CLIENT 2\nProcess 2->UBUSD:4.1: Lookup:{objpath}
UBUSD-->UBUS CLIENT 2\nProcess 2:4.2: Reply data:{objpath, objid, objtype, signature}
Note left of UBUS CLIENT 2\nProcess 2: Signature includes \nmethods and required \nparameters of each method.
UBUS CLIENT 2\nProcess 2->UBUSD:5.1: Invoke:{objid, method, msg}
UBUSD->UBUS CLIENT 1\nProcess 1:5.2: Invoke:{objid, method, msg}
UBUS CLIENT 1\nProcess 1-->UBUSD:5.3: Reply data:{objid, msg}
UBUSD-->UBUS CLIENT 2\nProcess 2:5.4: Reply data:{objid, msg}
UBUS CLIENT 2\nProcess 2->UBUSD:6.1: Remove:{objid}
UBUSD->UBUSD:6.2:Update avl-tree
Note right of UBUSD:Remove object \nwith matched objpath.
UBUSD-->UBUS CLIENT 2\nProcess 2:6.2: Reply data:{objid}
```
#### Ubus Traffic
Directions:
-> ubusd to object
<- object to ubusd
```bash=0
Dir. Obj.ID Ubus.ID Message Type Message
-> 2d0a3716 #2d0a3716 hello: {}
<- 2d0a3716 #00000000 add_object: {"objpath":"gserver.host","signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> 47dfa5f0 #00000000 invoke: {"objid":-921749017,"method":"ubus.object.add","data":{"id":-862368938,"path":"gserver.host"}}
-> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862}
-> 2d0a3716 #00000000 status: {"status":0}
<- 47dfa5f0 #00000000 status: {"status":0,"objid":-921749017}
-> 41a666fd #41a666fd hello: {}
<- 41a666fd #00000000 lookup: {"objpath":"gserver.host"}
-> 41a666fd #00000000 data: {"objpath":"gserver.host","objid":-862368938,"objtype":619811862,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> 41a666fd #00000000 status: {"status":0}
<- 41a666fd #cc994b56 invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"}}
-> 2d0a3716 #41a666fd invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"},"user":"root","group":"root"}
<- 2d0a3716 #41a666fd data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}}
-> 41a666fd #cc994b56 data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}}
<- 2d0a3716 #41a666fd status: {"status":0,"objid":-862368938}
-> 41a666fd #cc994b56 status: {"status":0,"objid":-862368938}
-> b5d12db5 #b5d12db5 hello: {}
<- b5d12db5 #00000000 lookup: {"objpath":"gserver.host"}
-> b5d12db5 #00000000 data: {"objpath":"gserver.host","objid":-862368938,"objtype":619811862,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> b5d12db5 #00000000 status: {"status":0}
<- b5d12db5 #cc994b56 invoke: {"objid":-862368938,"method":"gserver_stop","data":{}}
-> 2d0a3716 #b5d12db5 invoke: {"objid":-862368938,"method":"gserver_stop","data":{},"user":"root","group":"root"}
<- 2d0a3716 #00000000 remove_object: {"objid":-862368938}
-> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862}
-> 2d0a3716 #00000000 status: {"status":0}
<- 2d0a3716 #b5d12db5 status: {"status":0,"objid":-862368938}
```
##### 1. Connection establishment of Gserver.
```bash=1
-> 2d0a3716 #2d0a3716 hello: {}
```
##### 2. Registration of Gserver object with provided method.
```bash=2
<- 2d0a3716 #00000000 add_object: {"objpath":"gserver.host","signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> 47dfa5f0 #00000000 invoke: {"objid":-921749017,"method":"ubus.object.add","data":{"id":-862368938,"path":"gserver.host"}}
-> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862}
-> 2d0a3716 #00000000 status: {"status":0}
<- 47dfa5f0 #00000000 status: {"status":0,"objid":-921749017}
```
##### 3. Connection establishment of Process 2.
```bash=7
-> 41a666fd #41a666fd hello: {}
```
##### 4. Object id lookup.
```bash=8
<- 41a666fd #00000000 lookup: {"objpath":"gserver.host"}
-> 41a666fd #00000000 data: {"objpath":"gserver.host","objid":-862368938,"objtype":619811862,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> 41a666fd #00000000 status: {"status":0}
```
##### 5. Request with object id, method, and required data(msg).
```bash=11
<- 41a666fd #cc994b56 invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"}}
-> 2d0a3716 #41a666fd invoke: {"objid":-862368938,"method":"gserver_post","data":{"id":123456,"data":987654321,"msg":"Hi!"},"user":"root","group":"root"}
<- 2d0a3716 #41a666fd data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}}
-> 41a666fd #cc994b56 data: {"objid":-862368938,"data":{"Gserver reply":"Request is being proceeded!"}}
<- 2d0a3716 #41a666fd status: {"status":0,"objid":-862368938}
-> 41a666fd #cc994b56 status: {"status":0,"objid":-862368938}
```
##### 6. Deregistration of object.
```bash=23
<- 2d0a3716 #00000000 remove_object: {"objid":-862368938}
-> 2d0a3716 #00000000 data: {"objid":-862368938,"objtype":619811862}
-> 2d0a3716 #00000000 status: {"status":0}
<- 2d0a3716 #b5d12db5 status: {"status":0,"objid":-862368938}
```
---
### 2. Subscribe/notify
Data flow of Subscribe/notify.
0. Startup of UBUSD.
1. Connection establishment of Process 1.
2. Registration of Process 1 object with provided method.
3. Connection establishment of Process 3.
4. Object id lookup.
5. **Client 3 subscribe with object id.**
6. **Notification process.**
7. **Client 3 unsubscribe with object id.**
#### Sequence Diagram
```sequence
UBUSD->UBUSD:0: create socket bind listen
UBUS CLIENT 1\nProcess 1->UBUSD:2.1: Regist object, method
UBUSD->UBUSD:2.2: Update Avl-tree
UBUS CLIENT 3\nProcess 3->UBUSD:3.1: Connect
UBUSD-->UBUS CLIENT 3\nProcess 3:3.2: Accept
UBUSD-->UBUS CLIENT 3\nProcess 3:3.3: Hello
UBUS CLIENT 3\nProcess 3->UBUSD:4.1: Lookup:{objpath}
UBUSD-->UBUS CLIENT 3\nProcess 3:4.2: Reply data:{objpath, objid, objtype, signature}
UBUS CLIENT 3\nProcess 3->UBUSD:5.1: Subscribe:{objid}
UBUSD->UBUSD:5.2: Update Subscription-tree
UBUSD-->UBUS CLIENT 1\nProcess 1:5.3: Notify:{objid(subscriber),\n active:true}
UBUS CLIENT 1\nProcess 1->UBUS CLIENT 1\nProcess 1:6.0 Trigger Notification
UBUS CLIENT 1\nProcess 1->UBUSD:6.1: Notify:{objid, msg}
UBUSD->UBUSD:6.2: Lookup Subscription-tree
UBUSD-->UBUS CLIENT 3\nProcess 3: 6.3: Invoke:{objid, msg}
UBUS CLIENT 3\nProcess 3->UBUSD: 7.1: Unsubscribe:{objid}
UBUSD->UBUSD: 7.2: Update\n Subscription-tree
UBUSD-->UBUS CLIENT 1\nProcess 1: 7.3 Notify:{objid(subscriber),\n active:false}
```
#### Ubus Traffic
```bash=0
Dir. Obj.ID Ubus.ID Message Type Message
-> 74f42091 #74f42091 hello: {}
<- 74f42091 #00000000 add_object: {"objpath":"gserver.host","signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> ea7bde21 #00000000 invoke: {"objid":-804320694,"method":"ubus.object.add","data":{"id":629913760,"path":"gserver.host"}}
-> 74f42091 #00000000 data: {"objid":629913760,"objtype":-429408539}
-> 74f42091 #00000000 status: {"status":0}
<- ea7bde21 #00000000 status: {"status":0,"objid":-804320694}
-> 478023e4 #478023e4 hello: {}
<- 478023e4 #00000000 add_object: {}
-> 478023e4 #00000000 data: {"objid":-1244318547}
-> 478023e4 #00000000 status: {"status":0}
<- 478023e4 #00000000 lookup: {"objpath":"gserver.host"}
-> 478023e4 #00000000 data: {"objpath":"gserver.host","objid":629913760,"objtype":-429408539,"signature":{"gserver_post":{"id":5,"data":5,"msg":3},"gserver_stop":{}}}
-> 478023e4 #00000000 status: {"status":0}
<- 478023e4 #00000000 subscribe: {"objid":-1244318547}
-> 74f42091 #00000000 notify: {"objid":629913760,"active":true}
-> 478023e4 #00000000 status: {"status":0}
~~~~~~Notification Trigger~~~~~~
<- 74f42091 #258bb8a0 notify: {"objid":629913760,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true}
-> 478023e4 #74f42091 invoke: {"objid":-1244318547,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true,"user":"root","group":"root"}
<- 478023e4 #00000000 unsubscribe: {"objid":-1244318547}
-> 74f42091 #00000000 notify: {"objid":629913760,"active":false}
```
##### 5. Subscribe with object id.
```bash=14
<- 478023e4 #00000000 subscribe: {"objid":-1244318547}
-> 74f42091 #00000000 notify: {"objid":629913760,"active":true}
-> 478023e4 #00000000 status: {"status":0}
```
##### 6. Notification process.
```bash=18
<- 74f42091 #258bb8a0 notify: {"objid":629913760,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true}
-> 478023e4 #74f42091 invoke: {"objid":-1244318547,"method":"gserver_post","data":{"id":123,"data":321,"msg":"abcdef"},"no_reply":true,"user":"root","group":"root"}
```
##### 7. Unsubscribe with object id.
```bash=20
<- 478023e4 #00000000 unsubscribe: {"objid":-1244318547}
-> 74f42091 #00000000 notify: {"objid":629913760,"active":false}
```
---
### 3. Event Boardcast
Data flow of Event Boardcast.
0. Startup of UBUSD.
1. Connection establishment.
2. **Receivers register to ubus event handler(objid:1) with interested event pattern.**
3. **Sender sends data to ubus event handler(objid:1) with event pattern. Ubus event handler boardcasts data to receivers registered with same event pattern.**
#### Sequence Diagram
```sequence
UBUSD->UBUSD:0: create socket bind listen
UBUS CLIENT 1\nProcess 1->UBUSD:1.1: Connect
UBUSD-->UBUS CLIENT 1\nProcess 1:1.2 Accept
UBUSD-->UBUS CLIENT 1\nProcess 1:1.3 Hello
UBUS CLIENT 2\nProcess 2->UBUSD:1.4: Connect
UBUSD-->UBUS CLIENT 2\nProcess 2:1.5 Accept
UBUSD-->UBUS CLIENT 2\nProcess 2:1.6 Hello
UBUS CLIENT 1\nProcess 1->UBUSD:2.1: Invoke:{objid, method:"register",\ndata:{object, pattern}}
UBUSD->UBUSD:2.2: Update Event \nRegistration-tree
UBUS CLIENT 2\nProcess 2->UBUSD:3.1: Invoke:{objid, method:"send",\ndata:{pattern, data}}
UBUSD->UBUSD:3.2: Lookup Event \nRegistration-tree
UBUSD-->UBUS CLIENT 1\nProcess 1:3.3: Invoke:{objid, method:pattern, data}
```
#### Ubus Traffic
```bash=0
Dir. Obj.ID Ubus.ID Message Type Message
-> 55484d34 #55484d34 hello: {}
<- 55484d34 #00000000 add_object: {}
-> 55484d34 #00000000 data: {"objid":-964689289}
-> 55484d34 #00000000 status: {"status":0}
<- 55484d34 #00000001 invoke: {"objid":1,"method":"register","data":{"object":-964689289,"pattern":"g_server"}}
-> 55484d34 #00000001 status: {"status":0}
-> b79aea68 #b79aea68 hello: {}
<- b79aea68 #00000001 invoke: {"objid":1,"method":"send","data":{"id":"g_server","data":{"str":"gemtek"}}}
-> 55484d34 #00000000 invoke: {"objid":-964689289,"method":"g_server","data":{"str":"gemtek"}}
-> b79aea68 #00000001 status: {"status":0}
<- 55484d34 #00000000 status: {"status":0,"objid":-964689289}
```
##### 2. Receivers register to ubus event handler.
```bash=5
<- 55484d34 #00000001 invoke: {"objid":1,"method":"register","data":{"object":-964689289,"pattern":"g_server"}}
-> 55484d34 #00000001 status: {"status":0}
```
##### 3. Sender send data to ubus event handler(objid:1) with event pattern. Ubus event handler boardcasts data to receivers registered with *same event pattern.
```bash=7
<- b79aea68 #00000001 invoke: {"objid":1,"method":"send","data":{"id":"g_server","data":{"str":"gemtek"}}}
-> 55484d34 #00000000 invoke: {"objid":-964689289,"method":"g_server","data":{"str":"gemtek"}}
```
---
## UBUS tools
OpenWrt provides four tools to access ubus
1. **Command-line ubus tool**
2. **C library libubus**
4. Ubus Lua module
### Command-line ubus tool
The command "ubus" allows user to interact with the ubusd server. Services registered to ubusd server can be accessed by this command tool.
#### Help output of command "ubus"
```bash
root@ugwcpe:/# ubus
Usage: ubus [<options>] <command> [arguments...]
Options:
-s <socket>: Set the unix domain socket to connect to
-t <timeout>: Set the timeout (in seconds) for a command to complete
-S: Use simplified output (for scripts)
-v: More verbose output
-m <type>: (for monitor): include a specific message type
(can be used more than once)
-M <r|t> (for monitor): only capture received or transmitted traffic
Commands:
- list [<path>] List objects
- call <path> <method> [<message>] Call an object method
- listen [<path>...] Listen for events
- send <type> [<message>] Send an event
- wait_for <object> [<object>...] Wait for multiple objects to appear on ubus
- monitor Monitor ubus traffic
```
#### list
To find out services currently running on the bus, just simply use the `ubus list` command. A complete list of all object registed with namespace will be shown.
```bash
root@ugwcpe:/# ubus list
block
csd
devmd
dhcp
diagnosticsd
dwpald
firewalld
log
network
network.device
network.interface
network.interface.iface_eth0_1
network.interface.iface_eth0_2
network.interface.iface_eth0_3
network.interface.iface_eth0_4
network.interface.iface_eth1
network.interface.lan
network.interface.loopback
network.interface.wan3
network.wireless
polld
servd
service
system
uci
wsd
```
To find out methods and the argument signatures provided by specific service/object, we can type the service namespace, `system`, after the command `list` and use the option `-v`.
```bash
root@ugwcpe:/# ubus -v list system
'system' @d1165900
"board":{}
"info":{}
"reboot":{}
"upgrade":{}
"done":{}
"watchdog":{"frequency":"Integer","timeout":"Integer","magicclose":"Boolean","stop":"Boolean"}
"signal":{"pid":"Integer","signum":"Integer"}
"sysupgrade":{"path":"String","prefix":"String","command":"String"}
"factoryreset":{"value":"String"}
"hostname":{"value":"String"}
```
#### call
To call method of specific object, we can use the `call` command. Here is an example of `call` command. As there is no required data in method `status`, we just need to type `info` after object `system`.
The method being called takes actions, says return message, or turn on/off other services, depends on its callback function. In this case, the method `info` of `system` returns a message with system information to the callee.
```bash
root@ugwcpe:/# ubus call system info
{
"localtime": 1610460661,
"uptime": 82303,
"load": [
196608,
196608,
196608
],
"memory": {
"total": 1021562880,
"free": 884396032,
"shared": 1159168,
"buffered": 9117696
},
"swap": {
"total": 0,
"free": 0
}
}
```
#### send
To send message to an event with specific event pattern, we can use the `send` command. The following example is sending data `{"str":"gemtek"}` to event `event_a`.
```bash
root@ugwcpe:/# ubus send event_a '{"str":"gemtek"}'
```
#### listen
Command `listen` is for listening to events. The following example is listening to event `event_a`. The console prints data of related event update.
```bash
root@ugwcpe:/# ubus listen event_a
{ "event_a": {"str":"gemtek"} }
```
#### wait_for
Command `wait_for` returns when object waited is registered.
```bash
root@(none):/# ubus wait_for gserver.host
root@(none):/#
```
#### monitor
Command `monitor` is for monitoring ubus traffic.
```bash
root@ugwcpe:/# ubus monitor
-> d17cae6a #00000003 status: {"status":0}
-> 23f12bf1 #23f12bf1 hello: {}
<- 23f12bf1 #00000001 invoke: {"objid":1,"method":"send","data":{"id":"event_a","data":{"str":"gemtek"}}}
-> 716e9a5f #00000000 invoke: {"objid":-2003009711,"method":"event_a","data":{"str":"gemtek"}}
-> 23f12bf1 #00000001 status: {"status":0}
<- 716e9a5f #00000000 status: {"status":0,"objid":-2003009711}
```
### Library libubus
#### Function for object registration
| Function | Description |
| -------- | -------- |
| `struct ubus_context *ubus_connect(const char *path)`|Connect the specified path, create and return the ubus context represented by the path. |
| `inline void ubus_add_uloop(struct ubus_context *ctx)` | Activate UBUS; this tells U-Loop to check for ubus events (listens to ubus). It is blocking function, meaning that once we call uloop_run, it is waiting for ubus to get something. |
| `int ubus_lookup_id(struct ubus_context *ctx, const char *path, uint32_t *id)` | This routine gets id from path. If it is successful, it returns UBUS_STATUS_OK, otherwise UBUS_STATUS_* error-code. |
| `void ubus_free(struct ubus_context *ctx)` | It is identical to ubus_shutdown() + freeing the context. |
| `int ubus_add_object(struct ubus_context *ctx, struct ubus_object *obj)` | Add a UBUS object into the list of objects to be queried. We must call this routine before doing ubus_lookup_id. |
| `int ubus_remove_object(struct ubus_context *ctx, struct ubus_object *obj)` | The opposite of ubus_add_object; called when we need to cleanup the pending request. |
#### Function for request
| Function | Description |
| -------- | -------- |
| `int ubus_invoke(struct ubus_context *ctx, uint32_t obj, const char *method, struct blob_attr *msg, ubus_data_handler_t cb, void *priv, int timeout)` | Invoke RPC indicated in passed parameter method. `cb` is the callback object for server object responding with data. |
| `int ubus_send_reply(struct ubus_context *ctx, struct ubus_request *req, struct blob_attr *msg)` | Send reply to the incoming object call, says `invoke`. |
#### Function for subscription
| Function | Description |
| -------- | -------- |
| `int ubus_register_subscriber(struct ubus_context *ctx, struct ubus_subscriber *obj)` | Register a callback object for receiving notifications from publisher. |
| `int ubus_subscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id)` | Subscribe to an object with a registed callback object. |
| `int ubus_unsubscribe(struct ubus_context *ctx, struct ubus_subscriber *obj, uint32_t id)` | Unsubscribe from the object. |
#### Function for event
| Function | Description |
| -------- | -------- |
| `int ubus_notify(struct ubus_context *ctx, struct ubus_object *obj, const char *type, struct blob_attr *msg, int timeout)` | Send notification to ubus, ubus invokes subscribers with data carried by the notification. |
| `int ubus_register_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev, const char *pattern)` | Register event handler `ev` to the event on ubus. |
| `int ubus_unregister_event_handler(struct ubus_context *ctx, struct ubus_event_handler *ev)` | Deregister event handler `ev` on ubus. |
| `int ubus_send_event(struct ubus_context *ctx, const char *id, struct blob_attr *data)` | Send data as an event with event pattern `id` to ubus. Ubus call related event handlers with the data. |
#### Sample code of server object
```c=1
#include <stdio.h>
#include <stdint.h>
#include <libubus.h>
#include <libubox/uloop.h>
#include <libubox/blobmsg_json.h>
/* Ubus method_call_functions */
static int gserver_post(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
static int gserver_stop(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg);
/* Enum for GSERVER policy order */
enum {
GSERVER_ID,
GSERVER_DATA,
GSERVER_MSG,
__GSERVER_MAX,
};
/* Ubus method policy */
static const struct blobmsg_policy gserver_policy[] =
{
[GSERVER_ID] = { .name="id", .type=BLOBMSG_TYPE_INT32},
[GSERVER_DATA] = { .name="data", .type=BLOBMSG_TYPE_INT32 },
[GSERVER_MSG] = { .name="msg", .type=BLOBMSG_TYPE_STRING },
};
static const struct blobmsg_policy gserver_stop_policy[] =
{
};
/* Ubus object methods */
static const struct ubus_method gserver_methods[] =
{
/* UBUS_METHOD(method_name, method_call_function, method_policy) */
UBUS_METHOD("gserver_post", gserver_post, gserver_policy),
UBUS_METHOD("gserver_stop", gserver_stop, gserver_stop_policy)
};
/* Ubus object type */
static struct ubus_object_type gserver_obj_type =
UBUS_OBJECT_TYPE("gserver_uobj", gserver_methods);
/* Ubus object */
static struct ubus_object gserver_object=
{
.name = "gserver.host", //objpath
.type = &gserver_obj_type,
.methods = gserver_methods,
.n_methods = ARRAY_SIZE(gserver_methods),
};
/* Ubus method_call_functions */
static int gserver_post(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg) {
/* do something */
return 0;
}
static int gserver_stop(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg) {
/* do something */
return 0;
}
void server(void) {
/* 1. create an epoll instatnce descriptor poll_fd */
uloop_init();
/* 2. connect to ubusd and get ctx(context) */
struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path
/* 3. registger epoll events to uloop, start socket listening */
ubus_add_uloop(ctx);
/* 4. register a ubus_object to ubusd */
ubus_add_object(ctx, gserver_object);
/* 5. uloop routine: events monitoring and callback provoking */
uloop_run();
/* 6. terminate uloop */
uloop_done();
return;
}
```
#### Sample code of client object
```c=
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libubus.h>
#include <libubox/uloop.h>
#include <libubox/blobmsg_json.h>
static struct ubus_context *ctx;
static struct ubus_request_data req_data;
static struct blob_buf b_buf; //message carried in invoke
static uint32_t obj_id;
/* Ubus object */
static struct ubus_object client_object = {
};
/* callback */
static int callback (struct ubus_request *req,
int type, struct blob_attr *msg) {
/* do something */
return 0;
}
void client(void) {
/* 1. create an epoll instatnce descriptor poll_fd */
uloop_init();
/* 2. connect to ubusd and get ctx(context) */
struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path
/* 3. registger epoll events to uloop, start socket listening */
ubus_add_uloop(ctx);
/* 4. register a ubus_object to ubusd */
ubus_add_object(ctx, &client_object);
/* 5. lookup object_id of service object */
ubus_lookup_id(ctx, "gserver.host", &obj_id);
/* 6. send request by ubus_invoke to service object */
ubus_invoke(ctx, obj_id, "gserver_post", b_buf, callback, 0, 3000);
/* 7. uloop routine: events monitoring and callback provoking */
uloop_run();
/* 8. terminate uloop */
uloop_done();
return;
}
```
#### Sample code for subscriber
```c=
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libubus.h>
#include <libubox/uloop.h>
#include <libubox/blobmsg_json.h>
static struct ubus_context *ctx;
static uint32_t obj_id;
static int notif_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg) {
/* do something */
return 0;
}
void subscriber_object(void) {
/* 1. create an epoll instatnce descriptor poll_fd */
uloop_init();
/* 2. connect to ubusd and get ctx(context) */
struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path
/* 3. registger epoll events to uloop, start socket listening */
ubus_add_uloop(ctx);
/* 4. register a ubus_object to ubusd */
ubus_add_object(ctx, &subscriber_object);
/* 5. lookup object_id of service object */
ubus_lookup_id(ctx, "gserver.host", &obj_id);
/* 6. subscribe service object */
ubus_subscribe(ctx, ¬if_handler, obj_id);
/* 7. uloop routine: events monitoring and callback provoking */
uloop_run();
/* 8. terminate uloop */
uloop_done();
return;
}
```
#### Sample code for event listener
```c=
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <libubus.h>
#include <libubox/uloop.h>
#include <libubox/blobmsg_json.h>
static struct ubus_context *ctx;
static struct ubus_request_data req_data;
static struct blob_buf b_buf;
static uint32_t obj_id;
static void receive_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
const char *method, struct blob_attr *msg) {
printf("Event received\n");
/* do something */
return;
}
int event_example () {
/* 1. create an epoll instatnce descriptor poll_fd */
uloop_init();
/* 2. connect to ubusd and get ctx(context) */
struct ubus_context *ctx = ubus_connect(NULL); // Use default UNIX sock path
/* 3. registger epoll events to uloop, start socket listening */
ubus_add_uloop(ctx);
/* 4. register event on ubus */
const char *event = "gevent";
struct ubus_event_handler ev = {
.cb = receive_event,
};
ubus_register_event_handler(ctx, &ev, event);
/* 5. uloop routine: events monitoring */
uloop_run();
/* 6. terminate uloop */
uloop_done();
return;
}
```
---
## References
[https://openwrt.org/docs/techref/ubus](https://openwrt.org/docs/techref/ubus)
[https://openwrt.org/docs/techref/libubox](https://openwrt.org/docs/techref/libubox)
[https://www.programmersought.com/article/32835484946/](https://www.programmersought.com/article/32835484946/)
[https://www.programmersought.com/article/26351479004/](https://www.programmersought.com/article/26351479004/)
[https://www.programmersought.com/article/48733667380/](https://www.programmersought.com/article/48733667380/)