ubus

ubus說明


更新記錄

item note
20160726 第一版
20161129 增加: ubus範例 ,ubusd & ubus程序
20170206 增加usbd內容

目錄


Ubus

  • OpenWrt micro bus architecture
  • To provide communication between various daemons and applications in OpenWrt an ubus project has been developed

Ubus Source

  • ubus.git
    OpenWrt system message/RPC bus

source

  • OpenWrt Chaos Calmer 15.05.1 r49118
item version download
ubus build_dir/target-mips_34kc_uClibc-0.9.33.2/ubus-2015-05-25 ubus-f361bfa.tar.gz
json-c build_dir/target-mips_34kc_uClibc-0.9.33.2/json-c-0.12 json-c-0.12-20140410.tar.gz
libubox build_dir/target-mips_34kc_uClibc-0.9.33.2/libubox-2015-11-08
build_dir/target-mips_34kc_uClibc-0.9.33.2/lua-5.1.5 lua-5.1.5.tar.gz
  • ubus相依下例tools

    • json-c
    • lua
    • libubox
  • json-c cross compile

    1
    2
    ./configure --prefix=$(ROOTFS_DIR) --build=i686-pc-linux-gnu --host=arm-hisiv200-linux --target=arm-hisiv200-linux CC=arm-hisiv200-linux-gcc
    make & make install

ubus範例

openwrt

  • ubus list

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    root@OpenWrt:~# ubus list
    dhcp
    log
    network
    network.device
    network.interface
    network.interface.lan
    network.interface.loopback
    network.interface.wan
    network.interface.wan6
    network.wireless
    service
    session
    system
    uci
  • ubus list -v network.interface.lan

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    root@OpenWrt:~# ubus list -v network.interface.lan
    'network.interface.lan' @3656e47f
    "up":{}
    "down":{}
    "status":{}
    "prepare":{}
    "dump":{}
    "add_device":{"name":"String","link-ext":"Boolean"}
    "remove_device":{"name":"String","link-ext":"Boolean"}
    "notify_proto":{}
    "remove":{}
    "set_data":{}

ubus command

  • ubus command
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    root@OpenWrt:~# 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

    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

ubus example

  • ubus

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /ubus-ex # ./server 
    Watching object 4f90a5c1: Success
    Object 4f90a5c1 went away

    /ubus-ex # ./client
    Avg time per iteration: 39 usec
    Subscribers active: 1
    Got fd from the server, watching...
    completed request, ret: 0
    Avg time per iteration: 51 usec
    Got line: msg1: test received a message: blah
    Sending count up to '100100'; string has length '592926'
    Server validated our count up to '100100'
    Avg time per iteration: 48 usec
    Avg time per iteration: 46 usec

    ~ # ubus list
    test
  • server test

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ~ # ubus list -v
    'test' @69f7a210
    "hello":{"id":"Integer","msg":"String"}
    "watch":{"id":"Integer","counter":"Integer"}
    "count":{"to":"Integer","string":"String"}

    ~ # ubus call test hello '{"id":1, "msg":"t11"}'
    {
    "message": "test received a message: t11"
    }
    ~ #

    ~ # ubus call test count '{"to":5, "string":"5"}'
    {
    "rc": 5
    }

server

[example server]
  • test_object

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    static const struct ubus_method test_methods[] = {
    UBUS_METHOD("hello", test_hello, hello_policy),
    UBUS_METHOD("watch", test_watch, watch_policy),
    UBUS_METHOD("count", test_count, count_policy),
    };

    static struct ubus_object_type test_object_type =
    UBUS_OBJECT_TYPE("test", test_methods);

    static struct ubus_object test_object = {
    .name = "test",
    .type = &test_object_type,
    .methods = test_methods,
    .n_methods = ARRAY_SIZE(test_methods),
    };
  • ubus list

    1
    2
    ~ # ubus list
    test
  • ubus list -v

    1
    2
    3
    4
    5
    ~ # ubus list -v
    'test' @47a0bfd5
    "hello":{"id":"Integer","msg":"String"}
    "watch":{"id":"Integer","counter":"Integer"}
    "count":{"to":"Integer","string":"String"}

client

  • test_client_object
    1
    2
    3
    4
    5
    6
    7
    8
    static void test_client_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
    {
    fprintf(stderr, "Subscribers active: %d\n", obj->has_subscribers);
    }

    static struct ubus_object test_client_object = {
    .subscribe_cb = test_client_subscribe_cb,
    };

ubusd & ubus程序

  • ubusd由下例組成

    1
    2
    ADD_EXECUTABLE(ubusd ubusd.c ubusd_id.c ubusd_obj.c ubusd_proto.c ubusd_event.c)
    TARGET_LINK_LIBRARIES(ubusd ubox)
  • ubus由下例組成

    1
    2
    cli.c
    libubus.so -lubox -lblobmsg_json libjson-c.so
  • libubus.so由下例組成

    1
    2
    ADD_LIBRARY(ubus SHARED libubus.c libubus-io.c libubus-obj.c libubus-sub.c libubus-req.c)                                                                                           
    TARGET_LINK_LIBRARIES(ubus ubox m)

ubusd

[ubusd flow]
  • server_fd
    1
    2
    3
    static struct uloop_fd server_fd = {
    .cb = server_cb,
    };
[Server_cb flow]
  • ubusd
    在ubusd在執行main之前會先執行ubusd_obj_init
    • ubusd_obj_init
    • 初始化avl_tree的3個變數:objects, obj_type, path
    • ubusd_event_init,初始化event_obj
1
2
3
4
5
6
7
static void __constructor ubusd_obj_init(void)
{
ubus_init_id_tree(&objects);
ubus_init_id_tree(&obj_types);
ubus_init_string_tree(&path, false);
ubusd_event_init();
}

libubus

libubus 數據結構

  • ubus_event_handler
  • ubus_context
    • sock: client sock
    • local_id
    • strcut avl_tree object : client端object鏈表頭

libubus 接口說明

  • ubus_context
    struct ubus_context ubus_connect(const char *path);
    初始化client端context結構,開啟連接ubusd

  • ubus_add_object
    int ubus_add_object(struct ubus_context ctx, struct ubus_object obj);
    make an object visible to remote connections

  • ubus_register_subscriber
    add a subscriber notifications from another object

ubus_msg_type note
UBUS_MSG_DATA data message response
ex. ubus_send_reply UBUS_ATTR_OBJID
ubus_send_msg (UBUS_MSG_DATA)
  • ubus_msg_attr

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    enum ubus_msg_attr {
    UBUS_ATTR_UNSPEC,

    UBUS_ATTR_STATUS,

    UBUS_ATTR_OBJPATH,
    UBUS_ATTR_OBJID,
    UBUS_ATTR_METHOD,

    UBUS_ATTR_OBJTYPE,
    UBUS_ATTR_SIGNATURE,

    UBUS_ATTR_DATA,
    UBUS_ATTR_TARGET,

    UBUS_ATTR_ACTIVE,
    UBUS_ATTR_NO_REPLY,

    UBUS_ATTR_SUBSCRIBERS,

    /* must be last */
    UBUS_ATTR_MAX,
    };
  • ubus_msg_status

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    enum ubus_msg_status {
    UBUS_STATUS_OK,
    UBUS_STATUS_INVALID_COMMAND,
    UBUS_STATUS_INVALID_ARGUMENT,
    UBUS_STATUS_METHOD_NOT_FOUND,
    UBUS_STATUS_NOT_FOUND,
    UBUS_STATUS_NO_DATA,
    UBUS_STATUS_PERMISSION_DENIED,
    UBUS_STATUS_TIMEOUT,
    UBUS_STATUS_NOT_SUPPORTED,
    UBUS_STATUS_UNKNOWN_ERROR,
    UBUS_STATUS_CONNECTION_FAILED,
    __UBUS_STATUS_LAST
    };

ubusd程序如下

來源:ubus 1

  • 新client连接时 创建struct ubus_client数据结构
    初始化client fd回调函数client_cb,并加入到全局clients avl_tree中进行维护

  • client_cb

    • ubusd_proto_receive_message
      • ubus_msg_send
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
struct ubus_msg_buf {
uint32_t refcount; /* ~0: uses external data buffer */
struct ubus_msghdr hdr;
struct blob_attr *data;
int fd;
int len;
};

struct ubus_msghdr {
uint8_t version;
uint8_t type;
uint16_t seq;
uint32_t peer;
} __packetdata;

hdr.type 定義如下
enum ubus_msg_type {
/* initial server message */
UBUS_MSG_HELLO,

/* generic command response */
UBUS_MSG_STATUS,

/* data message response */
UBUS_MSG_DATA,

/* ping request */
UBUS_MSG_PING,

/* look up one or more objects */
UBUS_MSG_LOOKUP,

/* invoke a method on a single object */
UBUS_MSG_INVOKE,

UBUS_MSG_ADD_OBJECT,
UBUS_MSG_REMOVE_OBJECT,

/*
* subscribe/unsubscribe to object notifications
* The unsubscribe message is sent from ubusd when
* the object disappears
*/
UBUS_MSG_SUBSCRIBE,
UBUS_MSG_UNSUBSCRIBE,

/*
* send a notification to all subscribers of an object.
* when sent from the server, it indicates a subscription
* status change
*/
UBUS_MSG_NOTIFY,

/* must be last */
__UBUS_MSG_LAST,
};

hdr.type 定義如下 :

  • UBUS_MSG_ADD_OBJECT
    创建内部object,回应一个类型为UBUS_MSG_DATA的报文,报文内容有由ubusd生成的UBUS_ATTR_OBJID

  • UBUS_MSG_LOOKUP
    查询object,根据请求报文UBUS_ATTR_OBJPATH查找对应的object
    使用ubusd_send_obj()函数把查询出object内容回应给查询请求者

  • UBUS_MSG_SUBSCRIBE
    订阅object,使用ubus_subscribe()函数订阅指定object

當ubusd收到event處理

ubusd處理下例兩種event

  • register
    • Register注册某个object事件,使用ubusd_alloc_event_pattern()函数创建事件对象并加入到全局patterns队列中
    • event內容如下
1
2
3
4
static struct blobmsg_policy evr_policy[] = {
[EVREG_PATTERN] = { .name = "pattern", .type = BLOBMSG_TYPE_STRING },
[EVREG_OBJECT] = { .name = "object", .type = BLOBMSG_TYPE_INT32 },
};
  • send
    • Send转发某个事件内容,使用ubusd_forward_event()函数把指定事件内容转发给此事件所属的object拥有者 事件报文内容
    • event內容如下
1
2
3
4
static struct blobmsg_policy ev_policy[] = {
[EVMSG_ID] = { .name = "id", .type = BLOBMSG_TYPE_STRING },
[EVMSG_DATA] = { .name = "data", .type = BLOBMSG_TYPE_TABLE },
};

kevent

  • The kevent() system call is used to register events with the queue, and return any pending events to the user.

參考來源