[openwrt] process communication using ubus

Posted by spheonix on Sat, 15 Jan 2022 23:47:19 +0100

1. What is openwrt

What is openwrt?

2. Introduction to UBUS

ubus by openwrt Interprocess communication in platform development provides a general framework. It makes the implementation of interprocess communication very simple, and ubus It has strong portability and can be easily transplanted to other countries linux Used on the platform. This article describes ubus The implementation principle and overall framework of.

ubus The source code can be Git library git://nbd.name/luci2/ubus.git obtains the GIT Library of its dependent ubox Library: git://nbd.name/luci2/ubox.git . 

3. Implementation framework of UBUS

The implementation of ubus is based on unix socket, that is, local socket, which is more efficient and reliable than inet socket for network communication. The implementation of unix socket client and server is similar to that of network socket. Readers can refer to relevant materials if they are not familiar with it.

To implement a simple unix socket server and client, you need to do the following:

 1.Build a socket server End, bound to a local socket File and listen clients Connection of.
 2.Create one or more socket. 
 3.client End, connection server.  client and server Send messages to each other.
 4.client or server After receiving the other party's message, process the specific message accordingly.

The above components are also implemented in ubus, and the socket connection, message transmission and processing are encapsulated:

 1. ubus Provides a socket server: ubusd. Therefore, developers do not need to implement it themselves server End. 
 2. ubus Provides the ability to create socketclient And provides three ready-made clients for direct use by users: 
 		1,by shell Provided by script client End.
        2,by lua Provided by script client Interface.
        3,by C Language provided client Interface.
        ubus yes shell and lua Added support.
 3. ubus yes client and server The message format of communication between is defined: client and server All messages must be encapsulated into json Message format.
 4. ubus yes client The message processing at the end abstracts the "object"( object)"And "method"( method)"The concept of. An object contains multiple methods, client Need to server Registration received specific json How to handle messages. Objects and methods have their own names. The sending requester only needs to specify the names of the objects and methods to be called in the message

.

Some dynamic libraries need to be referenced when using Ubuntu, mainly including:

 1. libubus.so: ubus Programming interfaces provided externally, such as creating socket,Interface functions such as listening, connecting and sending messages.
 2. libubox.so: ubus Programming interfaces provided externally, such as waiting and reading messages.
 3. libblobmsg.so,libjson.so: Provides encapsulation and parsing json The data interface does not need to be used directly during programming libjson.so,But use libblobmsg.so Provides more flexible interface functions.

The relationship of components in ubus is shown in the following figure:

4. Implementation principle of UBUS

The following is an example to illustrate the working principle of ubus:
In the following figure, client2 attempts to modify the ip address through ubus, and the function to modify the ip address is defined in client1.

The whole process of client2's request is as follows:

1. client1 towards ubusd Two objects are registered:“ interface"And“ dotalk",Among them“ interface"Object method: "getlanip"And“ setlanip",The corresponding processing functions are func1()and func2(). "dotalk"Object method: "sayhi"And“ saybye",The corresponding processing functions are func3()and func4(). 

2. Then create a client2 Used with client1 Communication, attention, two client There is no direct communication between them, which needs to be approved ubusd(server)Transit.

3. client2 That's what I mentioned earlier shell/lua/C client. Suppose you use it here shell Client, enter the following command at the terminal: ubus call interface setlanip '{"ip":"10.0.0.1", "mask":24}'
4. Message sent to server After, server Based on the object name, it is found that the request should be forwarded to client1,Then send the message to client1,client1 Then call func2()Accept the parameters and process them. If you need to reply after processing client2,Send a reply message.

5. Application scenarios and limitations of UBUS

ubus can be used for communication between two processes and data interaction in a json like format. Common scenarios for Ubuntu are:

 1. "client–The server"Formal interaction, i.e. process A Register a series of services and processes B To call these services. 
 2. ubus Support to"Subscription - Notification"Process communication, that is, process communication A Provide subscription service. Other processes can choose to subscribe to or unsubscribe from the service A Messages can be sent to all subscribers.

Due to the limitation of ubus implementation, it is not suitable to use ubus in some scenarios:

 1. ubus It is used for the transmission of a small amount of data. If the amount of data is large or the data interaction is very frequent, it should not be used ubus. After testing, when ubus The amount of data transmitted at one time exceeds 60 KB,It won't work properly.
 2. ubus Poor support for multithreading, such as requesting the same service in multiple threads, may have unpredictable results.
 3. Recursive calls are not recommended ubus,For example, process A To call the process B Service, and B The service needs to call the process C Service, after C Return results to B,then B Return results to A. If you have to do this, you need to avoid the reuse of global variables during the call.

6. Brief analysis of UBUS source code

The following describes the code flow of ubusd and ubus client when they work. Here, for ease of understanding, only the general flow is introduced. For detailed implementation, please read the source code by yourself.

ubusd workflow
The initialization of ubusd is as follows:

 1. epoll_create(32)Create a poll_fd.  
 2. Create a UDP unix socket,And add to poll_fd Listening queue for.
 3. conduct epoll_wait()Wait for the message. The processing function after receiving the message is defined as follows: 
 static struct uloop_fd server_fd= {   
 .cb = server_cb,
 };

The server is called_ Cb() function.

1.server_ The work in the cb() function is:

 1. conduct accept(),accept client Connect and generate a client_fd.  
 2. by client Assign a clientid,be used for ubusd Distinguish between different client.  
 3. towards client Send a HELLO Message as a sign of connection establishment.
 4. take client_fd Add to poll_fd In the listening queue for listening client The message processing function is client_cb(). 

That is, ubusd listens to two kinds of messages, one is the connection request of a new client, and the other is the data sent by each existing client.
When ubusd receives a client data, it calls client_. Processing procedure of cb() function:

  1. First check whether there is any data that needs to be replied to this client (it may be that the last request was not processed). If so, send these legacy data first.
  2. Read the data on the socket and call the corresponding processing function according to the message type (the message type is specified in the data). The message type and processing function are defined as follows:
static const ubus_cmd_cb handlers[__UBUS_MSG_LAST] = {  
[UBUS_MSG_PING] = ubusd_send_pong,  
[UBUS_MSG_ADD_OBJECT] = ubusd_handle_add_object,  
[UBUS_MSG_REMOVE_OBJECT] = ubusd_handle_remove_object,  
[UBUS_MSG_LOOKUP] = ubusd_handle_lookup,  
[UBUS_MSG_INVOKE] = ubusd_handle_invoke,  
[UBUS_MSG_STATUS] = ubusd_handle_response,  
[UBUS_MSG_DATA] = ubusd_handle_response,  
[UBUS_MSG_SUBSCRIBE] = ubusd_handle_add_watch,  
[UBUS_MSG_UNSUBSCRIBE] = ubusd_handle_remove_watch,  
[UBUS_MSG_NOTIFY] = ubusd_handle_notify,  
};  

For example, if you receive an invoke message, call ubusd_ handle_ The invoke() function handles. These processing functions may need to send back data to the client after processing by ubusd, or forward the message to another client (if the client sending the request needs to communicate with another client).

After processing, report to client Send processing results, for example UBUS_STATUS_OK. (be careful, client Send data yes UBUS_MSG_DATA Type)

Workflow of client
Workflow of ubus call obj method:

 1. Create a unix socket(UDP)connect ubusd,And received server Sent it HELLO News. 
 2. ubus call Command by ubus_cli_call()Function, first ubusd send out lookup Message request obj of id. Then to ubusd send out invoke Message to call obj of method method.
 3. establish epoll_fd And will client of fd Add to the listening list and wait for messages.
 4. client The processing function after receiving the message is ubus_handle_data(),among UBUS_MSG_DATA Type of data  receive_call_result_data()Function to assist in parsing.

Workflow of the call ed client:

and ubus The process of the client is similar, but it becomes to accept the request and call the handler.

Topics: Linux openwrt