sysrepo
sysrepo - 1.4.2 笔记
1. sysrepo 概述
Sysrepo
是 Linux/Unix
系统下一个基于 YANG
模型的配置和操作数据库,为应用程序提供统一的操作数据的接口。应用程序使用 YANG
模型来建模,通过利用 YANG
模型完成数据合法性的检查,保证的风格的一致,不需要应用程序直接操作配置文件的一种数据管理方式。
1.1 基本特性与原则
sysrepo
只是一个库,不是一个独立的进程- 全部的数据始终由
Yang
模型区分,这就可能造成许多严重的后果,例如,允许同时使用不同的模型进行工作,这将可 导致数据访问时异常。 - 在所有有
IPC
中使用共享内存的方式,取代了之前的 UNIX中进程间通信的方式,这样更高效,性能更优,扩展性更强 - 在
sysrepo
中几乎不存在 CPU 时间浪费,没有活动等待或者定期检查 - 完全可定制化的事件处理,从定期检查或者
poll/select
到自动线程处理 - 访问控制严格受制于文件系统的权限
sysrepo
操作期间可以修改Yang
模型
1.2 主要特点
sysrepo
的主要功能是使用YANG
模型对数据进行操作并订阅各种事件。但是,在执行任何操作时,都需要创建会话,连接会话,并要install
所支持的各类Yang
模型。假如设置了日志操作记录,sysrepo
在运行时,也可以保留它的行为记录。- 通过
Yang
的xpath
来修改与获取数据,所以要求了解xpath
的基础知识。 - 最常见的操作订阅事件和修改订阅事件,订阅事件是允许应用程序根据特定的事件回调相应的数据执行,更改操作。操作执行成功后,会将对应配置操作保存,这样
sysrepo
可以充当更智能的配置文件,从而保证配置的可恢复性。 - 也支持
Rpc/Action/Notify
的订阅,这样可以通过执行特别的Rpc
,就可以分别向其他sysrepo
客户端通知各种生成的事件。
1.3 访问方法
应用程序可以通过两种方法来访问 sysrepo
,一种是直接的方法,即当应用程序需要配置数据或者执行相应的 callback
来响应配置变化时,可以通过 sysrepo
自带的应用程序来触发用 sysrepo
的功能函数来实现。这种方法一般用于开发人员自测或验证某个模块时使用;另一种是间接的方法,即应用程序通过创建 Deamon
进程的方法,该方法是通过将对 sysrepo
的调用转化为对应用程序的特定操作,该方法也最容易扩展,也无需为了使用 sysrepo
数据库而做相应的更改。如果有多个类似的 Deamon
进程,可以将这些进程合成一个 plugind
,最后由一个进程统一纳管。可扩展性得到大大的提高。间接方法的使用如图所示:
1.4 数据库
数据库结构大多是遵循 NMDA
(网络管理数据存储区体)所定义的体系架构。sysrepo
同样也不例外,sysrepo
中定义了四类数据库,分别是 startup
,running
,candidate
和 operational
。
startup
库,是sysrepo
中唯一的持久性数据存储库,它包含设备启动时的配置文件,系统启动后创建的第一个sysrepo
连接(共享内存)时,会将配置文件从startup
库copy
到running
库;running
数据库,是保存当前所运行时系统配置,当一个配置发生变化时并且设备需要重新配置时,running
数据库需要修改。系统重启时不会存在,如果需要,可以将配置copy
到startup
库。candidate
数据库,候选库,顾名思义,它是一个准备配置的数据但又不影响实际设备使用。虽然该库中的数据不限制设备的正常使用,可以不必严格按照 NETCONF协议的定义,但也是需要遵循一般的数据存储规则。该库正常是无效的,实际使用时,需要将该库mirror
到running
,由running
完成修改和配置下发,最后通过sr_copy_config()
, 将candidate
库重置。整个会话的过程中可能需要相应的lock
操作,来保证操作的一致与完整性。operational
库,维护当前使用的配置,并且该库只可读。它通常与对应的running
库有所不同,而且,只包含任何状态数据结点。在默认的情况下,该库是空的,对于用户来说,全部的订阅数据和操作数据都存储于operational
库中。并且Notificationg RPC/Action
数据的校验都是在operational
库是完成。
1.5 运行模式
- 对于连接与会话来说,会话是不同步的,所以不会在多个线程中共享一个会话。每个线程都需要建立属于自己的会话,来确保本线程运行的正确。
- 对于订阅来说,可以由应用程序对感兴趣的事件通过
*_subscribe()
函数来做相应的订阅。订阅在原则上是将全部的的事件一并处理,应用程序也可以将根据不同的事件类型拆分成多个不同的订阅,用于保证事件的并发处理。 - 每个订阅可以由不同的方式处理,这个由
sysrepo
做统一管理。sysrepo
创建一个单独的线程来捕获各种订阅事件的发生,然后通过订阅所注册的回调函数不处理它们。
2. sysrepo 常用操作命令
sysrepo
提供两个独立的,非常实用的程序。方便开发者便捷地使用 sysrepo
来开发与调试自己的应用。
2.1 Sysrepoctl
sysrepoctl
,它用于列出,安装,卸载或更新 sysrepo
模块,也能用于修改一个 sysrepo
模块的特性,权限等。开发过程中经常使用的命令如下
1 | 列出全部已经安装在 sysrepo 中的 Yang 模块,并包含模块的基本信息 |
1 | 安装指定 Yang 模型 |
1 | 卸载已安装的 Yang 模型 |
1 | 修改 Yang 模型,常用的是设置模型支持的特性 |
1 | 更新 Yang 模型,如果已安装的 Yang 模型有更新,可以执行该命令 |
更多 sysrepoctl
的使用,请参考 sysrepoctl -h
。
2.2 sysrepocfg
sysrepocfg
是用于 importing
,exporting
,editing
,replacing
配置到指定的数据库中。命令默认是操作 running
库,也支持多种数据格式,json
, xml
, lyb
,除非通过 –format
特定指出,默认的采用 xml
格式。常用的命令如下:
1 | 导入一个配置 |
1 | 导出一个配置 |
1 | 编辑或修改配置文件,应用到指定的数据库 |
1 | 发一个 RPC 请求,RPC 返回的结果直接输出于终端 |
更多 sysrepocfg
的使用,请参考 sysrepocfg -h
。
3. sysrepo-plugind 源码分析
应用程序通过将对 sysrepo
的调用通过 sysrepo
提供的相应的 API接口访问方法,称为 syrepo
的间接访问方法。该方法是应用程序通过创建 Deamon进程,通过 IPC Shm
机制与 sysrepo
通信。可以做到对 sysrepo
的即插即用,最后由 sysrepo
纳管,这就是 Plugind
,命名为 sysrepo-plugind
。要快速的使用 sysrepo
,并快速开发出适配于 sysrepo
的插件,就要先了解 sysrepo-plugind
的实现原理与机制,就需要先从实现 sysrepo-plugind
的源码处着手。sysrepo
源码路径:git clone https://github.com/sysrepo/sysrepo.git
。 Sysrepo-plugind
实现的路径为 sysrepo/src/executables/sysrepo-plugind.c
。下面也就从该文件开始说。
3.1 数据结构
1 | struct srpd_plugin_s { |
3.2 main 函数实现
1 | int main(int argc, char** argv) |
3.3 load_plugins
1 | static int |
3.4 init_cb
1 | // srpd_plugin_s 结构中定义了 init 的回调函数 |
3.5 cleanup_cb
1 | // srpd_plugin_s 结构中定义了 cleanup 的回调函数 |
整个 sysrepo-plugind.c
代码结构简单,注释丰富,没有使用复杂的语法,还是非常容易理解的。
4. sysrepo 连接与会话
4.1 何为连接与会话
开发者要开始使用 sysrepo
,首先必须创建一个连接。一个应用程序或者进程即使可以允许创建多个连接,但是一般情况只会创建一个连接。sysrepo
允许同时创建多个连接。简单的举个例子,通常情况下,sysrepo-plugin
在 init_cb
初始时就会创建一个连接,这是一个由 sysrepo-plugin
与 sysrepo
所创建的连接,只要发生异常不释放,该连接会一直存在整个 sysrepo-plugin
进程的生命周期,此外,例如用户通过 sysrepoctl -l |grep ***
看某个 Yang
模型是否已经加载,sysrepoctl
应用程序也创建一个短连接,该连接在命令执行结束后立即释放,假如是极端修改,不释放该连接,再使用 sysrepocfg
来配置 runing
库,这时有 3 个与 sysrepo
连接。并且 3 个连接不干扰,也不影响 sysrepo
的正常工作。
而会话,是建立在连接之下,一个连接下可以创建多个会话,每个会话都有一个唯一的标识,每个会话总是可以选择一个可随时更改的数据库,使用些会话的所有 API 调用都将在该数据库下操作。
连接与会话的关系如下所示,可能不是特别准备,但大概就是这个意思。
4.2 核心数据结构
connection
的数据结构主要是存储 sysrepo
连接与 Libyang
的上下文,该连接所创建的共享内存结构。数据结构定义如下
1 |
|
cache
需要特别说明:如果一个会话工作在 running
的数据库下操作,并且该会话的连接使能 cache
功能,则不会每次都从 sysrepo
中加载数据,可以从 cache
中复制数据,这样,可以大幅度提高 sysrepo
的处理性能。
session
的主要数据结构
1 | /** |
从 session
结构中主要是用于该次 session
的连接,该次 session
要连接的数据库类型(4种,runing
, startup
, candidate
, operation
),以及重中之重的 sr_subscription_ctx_t **subscriptions
, sysrepo
的所支持操作的订阅都在该结构中定义,不多说,直接看数据结构定义:
1 | /** |
4.3 connection 函数
1 | /*功能:连接sysrepo数据库 |
1 | /* 功能:清除与释放由sr_connect分配的的连接上下文, |
4.4 session
1 | /*功能:开始一个新的session |
1 | /* 功能:停止当前session并且释放与该session所维系的全部资源 |
连接与会话核心处就是这 4 个 API 函数, 其它与连接与会话有关的 API 都是对相关的补充,想要进一步了解的.请阅读源码.
接下来会分析 sysrepo
的共享内存机制. SHM
机制是新 sysrepo
的核心,需要好好说道说道.
5. sysrepo 共享内存机制
5.1 共享内存机制
sysrepo0.X.X
版本使用的进程间通信的机制,在实际的使用过程中,出现了诸如数据不同步、数据处理TimeOut
、完成一次 Get
请求时,但实际处理的请求会较多,导致性能与规格上不去的各类问题。sysrepo-devel
分支开始引入共享机制后,合入到 sysrepo
的 Master
分支,也就是现在的 sysrepo1.X.X
版本。
简单说一说什么是共享内存,共享内存就是允许两个或多个进程共享一定的存储区,说白了,就是两个进程访问同一块内存区域,当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改,所以数据不需要在客户机和服务器端之间复制,数据直接写到内存,不用若干次数据拷贝,是一种最快的 IPC
。原理图如下所示,需要注意的是,共享内存本向并没有任何的同步与互斥机制,所以必须使用信号量来实现对共享内存的存取的同步。其它有关的共享内存的概念使用,网上有很多,可自行查阅理解。本处这分析与 sysrepo
相关的共享内存机制的使用。
5.2 数据结构
1 | /** |
5.3 源码分析
此添加 shm main
的入口代码,将全部模块以 lydmod
数据形式添加到 main SHM
中。参考前一章的 sr_connect
函数,这就是将在与 sysrepo
连接时,会将全部模块的加载到共享内存中。
1 | sr_error_info_t * |
共享内存间在初始操作,包括信号的创建与初始化,也是在 sr_connet
函数中处理。``sr_connet是
plugind与
sysrepo的连接入口,
SHM是在入口中初始的一种机制,用来保证
sysrepo与
plugind` 的通信高效,快速。
先用 sysrepo
共享内存机制为后面的各类订阅打个底。先了解一下 sysrepo
的共享内存机理的实现。
Reference
libyang – GitHub
netopeer2 – GitHub
sysrepo – GitHub
pyang – GitHub
libyang – Doc
libnetconf2 – Doc
sysrepo – Doc
pyang – Doc
XPath 教程 – RUNOOB.COM
XPath教程 – 易百教程
netopeer2 + sysrepo研究总结
sysrepo简单使用
第三章 sysrepo-plugind源码分析