openwrt之ubus机制

openwrt之ubus机制

最近工作上的项目使用的是openwrt,并且我负责的某一任务要获取网络状态,因此需要使用到ubus,以下内容仅为学习笔记。

1、openwrt简介

OpenWRT是一个高度模块化、高度自动化的嵌入式Linux系统,拥有强大的网络组件和扩展性,常常被用于工控设备、电话、小型机器人、智能家居、路由器以及VOIP设备中。 同时,它还提供了100多个已编译好的软件,而且数量还在不断增加,而OpenWrt SDK 更简化了开发软件的工序。

OpenWRT不同于其他许多用于路由器的发行版,它是一个从零开始编写的、功能齐全的、容易修改的路由器操作系统。实际上,这意味着您能够使用您想要的功能而不加进其他的累赘,而支持这些功能工作的[linux kernel](https://baike.baidu.com/item/linux kernel/765824)又远比绝大多数发行版来得新。

2、ubus

简介

ubus就是一个用于进程间通讯的通用框架。它具有很强的可移植性,能够很方便的移植到其余的Linux平台上使用。

ubus模块被设计用于提供守护进程(daemons)和应用程序(applications)间的通信,包含了守护进程ubusd、库以及一些例子。ubusd能够认为是一个消息管理服务器(Server),须要通讯的进程能够经过提供的libubus使用ubus,而ubus又依赖于ubox。其源码下载地址以下:web

ubus:git://nbd.name/luci2/ubus.git或者http://git.openwrt.org/project/ubus.git
ubox:git://nbd.name/luci2/ubox.gitshell

ubus的内部框架大体如下图:

在这里插入图片描述

其中的Ubus Daemon就是ubusd,它是一个服务管理的服务器。上图右下角的组件是一个Client,用于向ubusd请求服务。而左下角是一个服务提供者(相对于ubusd它其实也是个Client,这里称之为Server实际上是相对于服务请求者Client而言,不要搞混了)。上图中Server和Client之间通讯的消息采用json格式。

名词解释

对象(object):

为了便于对消息进行处理,ubusd抽象出了“对象”和“方法”的概念。一个对象中包含多个方法,它们都可以指定名字,便于其余地方使用。多线程

扫描二维码关注公众号,回复: 13002204 查看本文章

方法(Method)

方法是对象提供的一些能够被调用的操做。在使用ubus调用(Call)某个方法时,Client会发送call消息给服务提供端,并等待回复。架构

通知(Notification)& 订阅者(Observer)

订阅者只关心本身感兴趣的服务,通知者经过该服务广播消息,通知全部的订阅者。它们之间是多对一的关系。

ubus进程间通信方式

ubus进程间通信方式总共有三种:P2P方式;Subscribe-notify方式;Event broadcast方式。

1)P2P方式:1对1

对于提供服务(Service)的进程(服务提供者)

  • 使用ubus_connect链接到服务管理进程ubusd,获得ubus_context(包含了链接fd、注册fd的回调等)
  • 经过ubus_add_uloop将ubus_context里包含的链接fd加入到epoll的描述符集,用于监听
    注意:在使用ubus前必需要调用uloop_init准备好epoll专用句柄。
  • 将定义的对象经过ubus_add_object加入到ubusd
  • 调用uloop_run循环epoll的文件描述符集
  • 资源释放
    若是不想再使用ubus,要依次调用ubus_free和uloop_done将前面申请的资源释放掉。

对于获取服务的请求进程(client)

  • 调用ubus_connect链接到ubusd,获得ubus_context

  • 经过ubus_add_uloop将ubus_context里包含的链接fd加入到epoll的描述符集,用于监听
    注意:在使用ubus前必需要调用uloop_init准备好epoll专用句柄。

  • 调用ubus_lookup_id查找对象对应的id
    在这里插入图片描述

  • 将调用参数填充到blob_buf
    ① 经过blob_buf_init初始化blob_buf
    ② 经过blobmsg_add_u32等函数往blob_buf中加入数据

  • 调用ubus_invoke,等待回应
    若是不须要等待回复,则调用ubus_invoke_async
    在这里插入图片描述

  • 资源释放
    若是不想再使用ubus,要依次调用ubus_free和uloop_done将前面申请的资源释放掉。

2)Subscribe-notify方式: 1对多
在这里插入图片描述

A是被订阅者,B,C,D是订阅者。

B,C,D通过ubusd订阅A,A通过ubusd向B,C,D广播消息

对于订阅者(Subscriber)

  • 调用ubus_connect链接到ubusd,获得ubus_context
  • 经过ubus_add_uloop将ubus_context里包含的链接fd加入到epoll的描述符集,用于监听
  • 定义ubus_subscriber实例并调用ubus_register_subscriber将其注册到ubusd
  • 订阅感兴趣的对象(Object)
  • 使用uloop_run函数,等待被订阅者广播消息。

对于通知发送者(Notifier,Notification Sender)

  • 调用ubus_connect链接到ubusd,获得ubus_context
  • 经过ubus_add_uloop将ubus_context里包含的链接fd加入到epoll的描述符集,用于监听
  • 定义一个通知对象(ubus_object)
  • ubus_add_object将通知对象加入到ubusd
  • 当事件发生,准备消息类型及参数
  • ubus_notify将通知广播到ubusd
  • 资源释放
    若是不想再使用ubus,要依次调用ubus_free和uloop_done将前面申请的资源释放掉。

3)Event broadcast方式: 1对多
在这里插入图片描述

A是广播者, B,C,D是监听者

A广播event,若event与B,C,D监听消息匹配,则B,C,D的相应处理函数被调用。

event是一个广播消息,事件的发送方不须要知道谁要接收这个消息。网卡的状态通知就是经过这种方式实现的,谁要是关心这个事件就本身接收处理。

实现的步骤和前面两种相似,这里只介绍不一样的部分。

对于事件接收者

  • 定义事件监听器ubus_event_handler
  • 调用ubus_register_event_handler注册事件处理机制

​ ubus_register_event_handler(ctx, ubus_event_handler, “eventA”);

对于事件发送者

  • 填充blob_buf,构造事件内容
  • 调用ubus_send_event将事件广播出去

​ ubus_send_event(ctx, “eventA", b.head);

对于事件发送者

  • 填充blob_buf,构造事件内容
  • 调用ubus_send_event将事件广播出去

​ ubus_send_event(ctx, “eventA", b.head);

参考文献

https://www.cnblogs.com/sky-heaven/p/6394267.html

猜你喜欢

转载自blog.csdn.net/weixin_42913061/article/details/115304503