14-Openwrt ubus

Ubus es el mecanismo de comunicación entre procesos en OpenWrt, ubusd implementa el servidor y otros procesos implementan al cliente, como ubus (cli), netifd y procd. Dos comunicaciones de cliente deben reenviarse a través del servidor.

ubus proporciona una interfaz para crear clientes de socket y proporciona tres clientes listos para que los usuarios los usen directamente:

  1. Lado del cliente para scripts de shell.
  2. Interfaz de cliente proporcionada para sua scripts.
  3. Interfaz de cliente para lenguaje C.

Aquí explicamos principalmente el lenguaje C y el shell

1 método ubus

ubusd ha sido implementado por openwrt, por lo que implementamos ubus en el lado del cliente, que también se basa en uloop, por lo que sus tres pasos también son necesarios:

void ubus_test(void)
{    
    uloop_init();
    ztest_ubus_init();
    uloop_run();
    ztest_ubus_clean();
    uloop_done();
}

Ubus llamando a los pasos ubus_connect, ubus_add_uloop, ubus_add_object

int ztest_ubus_init(void)
{
    int ret;

    g_ubus_ctx = ubus_connect(NULL);
    if (!g_ubus_ctx) {
        ULOG_ERR("Failed to connect to ubus\n");
        return -1;
    }

    g_ubus_ctx->connection_lost = ztest_ubus_connection_lost;
    ubus_add_uloop(g_ubus_ctx);

    ret = ubus_add_object(g_ubus_ctx, &ztest_object);
    if (ret)
        ULOG_ERR("Failed to add zboard object: %s\n", ubus_strerror(ret));

    return ret;
}

Principalmente implementamos el contenido de los métodos en el objeto Ztest_methods define todos los métodos del ubus actual y las funciones de devolución de llamada a las que se accede cuando se llama a cada método.

ubus abstrae los conceptos de "objeto" y "método" para el procesamiento de mensajes en el lado del cliente. Un objeto contiene múltiples métodos, y el cliente necesita registrarse con el servidor cuando recibe un mensaje json específico. Los objetos y métodos tienen sus propios nombres, y el remitente solo necesita especificar los nombres de los objetos y métodos a los que se llamará en el mensaje.

static const struct ubus_method ztest_methods[] = {
    { .name = "set_test", .handler = ztest_set_test },
    { .name = "get_test", .handler = ztest_get_test },
};

static struct ubus_object_type ztest_object_type =
    UBUS_OBJECT_TYPE("ztest", ztest_methods);

static struct ubus_object ztest_object = {
    .name = "ztest",
    .type = &ztest_object_type,
    .methods = ztest_methods,
    .n_methods = ARRAY_SIZE(ztest_methods),
};

Una vez definidos los métodos, es el contenido del método real. En este momento, las interfaces como blob y blobmsg en el libubox se utilizan para encapsular y analizar el formato de datos.

ubus define el formato del mensaje para la comunicación entre el cliente y el servidor: tanto el cliente como el servidor deben encapsular el mensaje en formato de mensaje json

enum {
    ZTEST_STATUS,
    ZTEST_PORT,
    ZTEST_MAX
};

static const struct blobmsg_policy zboard_policy[ZTEST_MAX] = {
    [ZTEST_STATUS] = { .name = "status", .type = BLOBMSG_TYPE_INT32 },
    [ZTEST_PORT] = { .name = "port", .type = BLOBMSG_TYPE_INT32 },
};

static uint32_t g_wan_status;
static uint32_t g_wan_port;

static int ztest_set_test(struct ubus_context *ctx, struct ubus_object *obj,
                        struct ubus_request_data *req, const char *method,
                        struct blob_attr *msg)
{
    struct blob_attr *tb[ZTEST_MAX];

    blobmsg_parse(zboard_policy, ZTEST_MAX, tb, blob_data(msg), blob_len(msg));

    if (!tb[ZTEST_STATUS] || !tb[ZTEST_PORT])
        return UBUS_STATUS_INVALID_ARGUMENT;

    g_wan_status = blobmsg_get_u32(tb[ZTEST_STATUS]);
    g_wan_port = blobmsg_get_u32(tb[ZTEST_PORT]);

    return 0;
}

static int ztest_get_test(struct ubus_context *ctx, struct ubus_object *obj,
                        struct ubus_request_data *req, const char *method,
                        struct blob_attr *msg)
{
    blob_buf_init(&g_bbuf, 0);
    blobmsg_add_u32(&g_bbuf, "status", g_wan_status);
    blobmsg_add_u32(&g_bbuf, "port", g_wan_port);
    ubus_send_reply(ctx, req, g_bbuf.head);

    return 0;
}

Para la prueba de ubus, generalmente usamos el método de shell para probar directamente con la herramienta ubus en la línea de comando, de la siguiente manera:

root@zihome:/usr/sbin# ubus list
log
network
network.device
network.interface
network.interface.lan
network.interface.loopback
network.interface.wan
network.wireless
nlwifi.wireless
service
session
system
uci
zboard
zdetect
ztest

Obtener método:

root@zihome:/usr/sbin# ubus list ztest -v
'ztest' @78782e2e
        "set_test":{}
        "get_test":{}

Establecer el mensaje de mensaje:

root@zihome:/usr/sbin# ubus call ztest get_test
{
        "status": 0,
        "port": 0
}
root@zihome:/usr/sbin# ubus call ztest set_test '{"status": 1, "port": 1}'
root@zihome:/usr/sbin# ubus call ztest get_test
{
        "status": 1,
        "port": 1
}

2.event_ubus

El evento de monitoreo ubus se usa a menudo. Después de que un proceso se configura para escuchar, cuando otro proceso envía un evento de notificación, ingresará a la función de devolución de llamada de monitoreo, que es muy útil para la comunicación entre procesos.

static void receive_event(struct ubus_context *ctx, struct ubus_event_handler *ev,
                          const char *type, struct blob_attr *msg)
{
    struct blob_attr *tb[ZTEST_MAX];

    ULOG_INFO("receive_event\n");
    blobmsg_parse(zboard_policy, ZTEST_MAX, tb, blob_data(msg), blob_len(msg));

    if (!tb[ZTEST_STATUS] || !tb[ZTEST_PORT])
        return;

    g_wan_status = blobmsg_get_u32(tb[ZTEST_STATUS]);
    g_wan_port = blobmsg_get_u32(tb[ZTEST_PORT]);
}

int ztest_ubus_event_init(void)
{
    int ret;
    static struct ubus_event_handler listener;
    
    memset(&listener, 0, sizeof(listener));
    listener.cb = receive_event;
    ret = ubus_register_event_handler(g_ubus_ctx, &listener, "test_event");
    if (ret){
        ULOG_ERR("ubus_register_event_handler error %s", ubus_strerror(ret));
    }
    return ret;
}

Use el shell para enviar eventos para probar

root@zihome:/usr/sbin# ubus call ztest get_test
{
        "status": 0,
        "port": 0
}
root@zihome:/usr/sbin# ubus send test_event '{"status": 1, "port": 3}'
root@zihome:/usr/sbin# ubus call ztest get_test
{
        "status": 1,
        "port": 3
}

Usa el shell para escuchar eventos de escucha

root@zihome:/usr/sbin# ubus listen
{ "test_event": {"status":1,"port":3} }
{ "test_event": {"status":1,"port":5} }

El código está en github: https://github.com/creatorly/TestCode/tree/master/openwrt/ztest

Blog de referencia:
https://blog.csdn.net/iampisfan/article/details/78107903

https://blog.csdn.net/jasonchen_gbd/article/details/45627967

https://blog.csdn.net/iampisfan/article/details/78107903
ubus también se basa en este conjunto de procesos, en los que ubusd implementa el servidor, y otros procesos implementan al cliente, como ubus (cli), netifd, prodc;
deben pasar dos comunicaciones de cliente Reenvío del servidor.

Análisis del código fuente de OpenWrt de libubox:
https://blog.csdn.net/iampisfan/article/details/78108100

Notas de estudio de OpenWrt netifd:
https://blog.csdn.net/jasonchen_gbd/article/details/74990247

106 artículos originales publicados · 76 elogiados · 130,000 visitas +

Supongo que te gusta

Origin blog.csdn.net/Creator_Ly/article/details/95798464
Recomendado
Clasificación