netopeer网络管理浅析简单介绍了基于netconf协议的netopeer项目是如何对实际设备进行管理的,基于对netopeer的学习,本节着手于对第二代netopeer2的研究,主要介绍netopeer2如何对实际设备进行管理,首先介绍如何读取当前linux系统的端口配置信息,实现类似于netopeer/transAPI/cfginterfaces/cfginterfaces-init的功能。
sysrepo简单使用中介绍了可以使用两种方式访问sysrepo数据库:独立进程形式和插件形式。
使用独立进程形式可以更好地进行打印输出,调试代码,以方便项目开发。
首先在sysrepo/examples/plugin目录下,创建一个sr_interfaces.c文件,main函数中创建与sysrepo的连接,并开启一个会话,然后利用开启的会话,读取linux系统端口信息,并将端口信息注册到sysrepo数据库,具体如下:
int
main(int argc, char **argv)
{
sr_conn_ctx_t *connection = NULL;
sr_session_ctx_t *session = NULL;
int rc = SR_ERR_OK;
unsigned int dev_count;
char **devices, *msg = NULL;
int i;
/* turn logging on */
sr_log_stderr(SR_LL_WRN);
/* connect to sysrepo */
rc = sr_connect(0, &connection);
if (rc != SR_ERR_OK) {
goto cleanup;
}
/* start session */
rc = sr_session_start(connection, SR_DS_RUNNING, &session);
if (rc != SR_ERR_OK) {
goto cleanup;
}
/* 获取linux系统端口*/
devices = iface_get_ifcs(1, &dev_count, &msg);
if(devices == NULL){
goto cleanup;
}
for(i = 0; i < dev_count; i++){
/* 解析端口信息,parse_iface_config函数的具体实现如下所示 */
rc = parse_iface_config(session, devices[i], &msg);
free(devices[i]);
if(msg != NULL){
free(msg);
msg = NULL;
}
}
free(devices);
/* apply the change */
rc = sr_apply_changes(session, 0, 0);
if (rc != SR_ERR_OK) {
goto cleanup;
}
cleanup:
sr_disconnect(connection);
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}
parse_iface_config函数的具体实现如下:
int parse_iface_config(sr_session_ctx_t *session, const char if_name, char **msg)
{
int i, j, rc, len;
unsigned int ipv4_enabled;
char *tmp, *tmp2;
struct ip_addrs ips;
char xpath0[128], xpath[128], xpath_ip[128];
char ianaift[64] = "iana-if-type:";
char ipaddr[64];
ips.count = 0;
strcpy(xpath0, "/ietf-interfaces:interfaces/interface[name='");
strcat(xpath0, if_name);
strcat(xpath0, "']");
printf("xpath0: %s\n", xpath0);
/* 设置一个interface节点,节点的name值为if_name指针指向的值 */
rc = sr_set_item_str(session, xpath0, NULL, NULL, SR_EDIT_DEFAULT);
if(if_name < (char*)2 || (tmp2 = iface_get_type(if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/type");
strcat(ianaift, tmp2);
rc = sr_set_item_str(session, xpath, ianaift, NULL, SR_EDIT_DEFAULT);
free(tmp2);
if((tmp = iface_get_enabled(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/enabled");
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
free(tmp);
/* IPv4 */
if((j = iface_get_ipv4_presence(1, if_name, msg)) == -1){
return -1;
}
if(j){
if((tmp = iface_get_ipv4_enabled(if_name, msg)) == NULL){
return -1;
}
if(strcmp(tmp, "true") == 0){
ipv4_enabled = 1;
}else{
ipv4_enabled = 0;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv4/enabled");
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
free(tmp);
if((tmp = iface_get_ipv4_forwarding(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv4/forwarding");
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
free(tmp);
if((tmp = iface_get_ipv4_mtu(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv4/mtu");
if(atoi(tmp) < 65536){
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
}
free(tmp);
if(ipv4_enabled){
if(iface_get_ipv4_ipaddrs(1, if_name, &ips, msg) != 0){
return -1;
}
for(j = 0; j < ips.count; ++j){
len = strlen(ips.ip[j]);
memcpy(ipaddr, ips.ip[j], len);
ipaddr[len] = '\0';
/* ipv4下添加一个address节点,节点的key属性ip的值为ipaddr */
memcpy(xpath_ip, xpath0, sizeof(xpath0));
strcat(xpath_ip, "/ietf-ip:ipv4/address[ip='");
strcat(xpath_ip, ipaddr);
strcat(xpath_ip, "']");
rc = sr_set_item_str(session, xpath_ip, NULL, NULL, SR_EDIT_DEFAULT);
printf("xpath_ip: %s\n", xpath_ip);
memcpy(xpath, xpath_ip, sizeof(xpath_ip));
strcat(xpath, "/prefix-length");
rc = sr_set_item_str(session, xpath, ips.prefix_or_mac[j], NULL, SR_EDIT_DEFAULT);
printf("xpath: %s\n", xpath);
free(ips.ip[j]);
free(ips.prefix_or_mac[j]);
}
if(ips.count != 0){
free(ips.ip);
free(ips.prefix_or_mac);
ips.count = 0;
}
}
}
/* IPv6 */
if((j = iface_get_ipv6_presence(1, if_name, msg)) == -1){
return -1;
}
if(j){
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv6/enabled");
rc = sr_set_item_str(session, xpath, "true", NULL, SR_EDIT_DEFAULT);
if((tmp = iface_get_ipv6_forwarding(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv6/forwarding");
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
free(tmp);
if((tmp = iface_get_ipv6_mtu(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv6/mtu");
if(strcmp("65535", tmp) < 0){
printf("mtu is too high");
}else{
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
}
free(tmp);
if(iface_get_ipv6_ipaddrs(1, if_name, &ips, msg) != 0){
return -1;
}
for(j = 0; j < ips.count; ++j){
len = strlen(ips.ip[j]);
memcpy(ipaddr, ips.ip[j], len);
ipaddr[len] = '\0';
memcpy(xpath_ip, xpath0, sizeof(xpath0));
strcat(xpath_ip, "/ietf-ip:ipv6/address[ip='");
strcat(xpath_ip, ipaddr);
strcat(xpath_ip, "']");
rc = sr_set_item_str(session, xpath_ip, NULL, NULL, SR_EDIT_DEFAULT);
printf("xpath_ip: %s\n", xpath_ip);
memcpy(xpath, xpath_ip, sizeof(xpath_ip));
strcat(xpath, "/prefix-length");
rc = sr_set_item_str(session, xpath, ips.prefix_or_mac[j], NULL, SR_EDIT_DEFAULT);
free(ips.ip[j]);
free(ips.prefix_or_mac[j]);
}
if(ips.count != 0){
free(ips.ip);
free(ips.prefix_or_mac);
ips.count = 0;
}
if(iface_get_ipv6_neighs(1, if_name, &ips, msg) != 0){
return -1;
}
for(j = 0; j < ips.count; ++j){
len = strlen(ips.ip[j]);
memcpy(ipaddr, ips.ip[j], len);
ipaddr[len] = '\0';
memcpy(xpath_ip, xpath0, sizeof(xpath0));
strcat(xpath_ip, "/ietf-ip:ipv6/neighbor[ip='");
strcat(xpath_ip, ipaddr);
strcat(xpath_ip, "']");
rc = sr_set_item_str(session, xpath_ip, NULL, NULL, SR_EDIT_DEFAULT);
memcpy(xpath, xpath_ip, sizeof(xpath_ip));
strcat(xpath, "/link-layer-address");
rc = sr_set_item_str(session, xpath, ips.prefix_or_mac[j], NULL, SR_EDIT_DEFAULT);
free(ips.ip[j]);
free(ips.prefix_or_mac[j]);
}
if(ips.count != 0){
free(ips.ip);
free(ips.prefix_or_mac);
ips.count = 0;
}
if((tmp = iface_get_ipv6_dup_addr_det(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv6/dup-addr-detect-transmits");
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
free(tmp);
if((tmp = iface_get_ipv6_creat_glob_addr(1, if_name, msg)) == NULL){
return -1;
}
memcpy(xpath, xpath0, sizeof(xpath0));
strcat(xpath, "/ietf-ip:ipv6/autoconf/create-global-address");
rc = sr_set_item_str(session, xpath, tmp, NULL, SR_EDIT_DEFAULT);
free(tmp);
}
return 0;
}
上述函数中用到的诸如iface_***函数均借鉴自netopeer/transAPI/cfginterfaces/目录下的iface_if.c中定义的函数,主要完成读取设备端口相关信息。
编译自己新增的函数方法为:在sysrepo/examples目录下的CMakeLists.txt文件中添加自己的函数,如:
add_executable(ietf-interfaces plugin/iface_if.c plugin/sr_interfaces.c)
target_link_libraries(ietf-interfaces sysrepo)
然后重新cmake .. && make,就会在sysrepo/build/examples目录下生成可执行程序。然后就可以运行自己的程序了。
在sysrepo/build/examples目录下执行:
[root@localhost examples]# ./application_changes_example ietf-interfaces
Application will watch for changes in "ietf-interfaces".
========== READING RUNNING CONFIG: ==========
/ietf-interfaces:interfaces (container)
========== LISTENING FOR CHANGES ==========
可以看到,当前状态下没有任何信息。另启一个终端,执行命令
[root@localhost examples]# ./ietf-interfaces
xpath0: /ietf-interfaces:interfaces/interface[name='ens32']
xpath0: /ietf-interfaces:interfaces/interface[name='lo']
xpath_ip: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']
xpath: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/prefix-length
终端打印输出是parse_iface_config函数中printf()函数的输出。
在监听端可以看到如下打印信息:
[root@localhost examples]# ./application_changes_example ietf-interfaces
Application will watch for changes in "ietf-interfaces".
[WRN]: Removing event pipe "sr_evpipe16" after a crashed subscription.
========== READING RUNNING CONFIG: ==========
/ietf-interfaces:interfaces (container)
========== LISTENING FOR CHANGES ==========
========== EVENT change CHANGES: ====================================
CREATED: /ietf-interfaces:interfaces/interface[name='ens32'] (list instance)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/name = ens32
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/type = iana-if-type:ethernetCsmacd
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/enabled = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/enabled = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/mtu = 1500
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/mtu = 1500
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/dup-addr-detect-transmits = 1
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/autoconf (container)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/autoconf/create-global-addresses = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo'] (list instance)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/name = lo
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/type = iana-if-type:softwareLoopback
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1'] (list instance)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/ip = 127.0.0.1
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/prefix-length = 8
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/dup-addr-detect-transmits = 1
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/autoconf (container)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/autoconf/create-global-addresses = true
========== END OF CHANGES =======================================
========== EVENT done CHANGES: ====================================
CREATED: /ietf-interfaces:interfaces/interface[name='ens32'] (list instance)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/name = ens32
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/type = iana-if-type:ethernetCsmacd
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/enabled = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/enabled = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/mtu = 1500
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/mtu = 1500
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/dup-addr-detect-transmits = 1
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/autoconf (container)
CREATED: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/autoconf/create-global-addresses = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo'] (list instance)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/name = lo
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/type = iana-if-type:softwareLoopback
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1'] (list instance)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/ip = 127.0.0.1
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/prefix-length = 8
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6 (container)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/enabled = true
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/forwarding = false
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/dup-addr-detect-transmits = 1
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/autoconf (container)
CREATED: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/autoconf/create-global-addresses = true
========== END OF CHANGES =======================================
========== CONFIG HAS CHANGED, CURRENT RUNNING CONFIG: ==========
/ietf-interfaces:interfaces (container)
/ietf-interfaces:interfaces/interface[name='ens32'] (list instance)
/ietf-interfaces:interfaces/interface[name='ens32']/name = ens32
/ietf-interfaces:interfaces/interface[name='ens32']/type = iana-if-type:ethernetCsmacd
/ietf-interfaces:interfaces/interface[name='ens32']/enabled = false
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4 (container)
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/enabled = false
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/forwarding = false
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/mtu = 1500
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6 (container)
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/enabled = true
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/forwarding = false
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/mtu = 1500
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/dup-addr-detect-transmits = 1
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/autoconf (container)
/ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv6/autoconf/create-global-addresses = true
/ietf-interfaces:interfaces/interface[name='lo'] (list instance)
/ietf-interfaces:interfaces/interface[name='lo']/name = lo
/ietf-interfaces:interfaces/interface[name='lo']/type = iana-if-type:softwareLoopback
/ietf-interfaces:interfaces/interface[name='lo']/enabled = true
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4 (container)
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/enabled = true
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/forwarding = false
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1'] (list instance)
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/ip = 127.0.0.1
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/prefix-length = 8
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6 (container)
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/enabled = true
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/forwarding = false
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/dup-addr-detect-transmits = 1
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/autoconf (container)
/ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv6/autoconf/create-global-addresses = true
可以看到,当前配置信息已经发生了改变,正确读取到系统端口配置信息。
此时,如果启动netopeer2-server和netopeer2-cli后,可以通过netopeer2-cli客户端看到相应端口信息。
sysrepo插件就是一个共享库文件,必须提供两个接口:sr_plugin_init_cb() 和 sr_plugin_cleanup_cb()。设备的初始化数据必须在sr_plugin_init_cb()接口中实现,将编译好的.so文件放入sysrepo插件路径下,其安装路径在cmake的时候指定,如下所示:
[root@bogon build]# cmake ..
-- ietf-yang-library revision: 2019-01-04
-- Sysrepo repository: /home/renzg/netopeer2/libnetconf2/sysrepo-master/build/repository
-- Startup data path: /home/renzg/netopeer2/libnetconf2/sysrepo-master/build/repository/data
-- Notification path: /home/renzg/netopeer2/libnetconf2/sysrepo-master/build/repository/data/notif
-- YANG module path: /home/renzg/netopeer2/libnetconf2/sysrepo-master/build/repository/yang
-- SRPD plugins path: /usr/local/lib64/sysrepo/plugins
-- Missing tools (devscripts, debhelper package) for building DEB package.
-- To build local RPM package, use "build-rpm" target.
-- Configuring done
-- Generating done
-- Build files have been written to: /home/renzg/netopeer2/libnetconf2/sysrepo-master/build
/usr/local/lib64/sysrepo/plugins即为sysrepo插件路径。
插件形式实现读取设备初始数据的代码如下:
int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_data)
{
int rc;
(void)private_data;
unsigned int dev_count;
char** devices, *msg = NULL;
int i;
/* remember the session of our plugin */
sess = session;
devices = iface_get_ifcs(1, &dev_count, &msg);
if (devices == NULL) {
goto error;
}
for(i = 0; i < dev_count; i++){
rc = parse_iface_config(session, devices[i], &msg);
free(devices[i]);
if(msg != NULL){
free(msg);
msg = NULL;
}
}
free(devices);
/* apply the change */
rc = sr_apply_changes(session, 0, 0);
if (rc != SR_ERR_OK) {
goto error;
}
printf("sr_apply_changes end\n");
/* sysrepo/plugins.h provides an interface for logging */
SRP_LOG_DBGMSG("OVEN: Oven plugin initialized successfully.");
return SR_ERR_OK;
error:
SRP_LOG_ERR("OVEN: Oven plugin initialization failed: %s.", sr_strerror(rc));
sr_unsubscribe(subscription);
return rc;
}
void
sr_plugin_cleanup_cb(sr_session_ctx_t *session, void *private_data)
{
(void)session;
(void)private_data;
/* nothing to cleanup except freeing the subscriptions */
sr_unsubscribe(subscription);
SRP_LOG_DBGMSG("OVEN: Oven plugin cleanup finished.");
}
然后在sysrepo/examples/CMakeLists.txt文件中添加自己的.c文件
# ietf-interfaces plugin
add_library(ietf-interfaces MODULE plugin/iface_if.c plugin/interfaces.c)
set_target_properties(ietf-interfaces PROPERTIES PREFIX "")
target_link_libraries(ietf-interfaces sysrepo)
编译sysrepo源码,会在exampls文件夹下生成ietf-interfaces.so文件,将该文件复制到/usr/local/lib64/sysrepo/plugins目录下,执行sysrepo-plugind即可,如下所示:
[root@bogon build]# sysrepo-plugind -v3 -d
[INF]: Applying scheduled changes.
[INF]: No scheduled changes.
[INF]: Session 5 (user "root") created.
xpath0: /ietf-interfaces:interfaces/interface[name='ens32']
xpath: /ietf-interfaces:interfaces/interface[name='ens32']/type, ianaift: iana-if-type:ethernetCsmacd
xpath: /ietf-interfaces:interfaces/interface[name='ens32']/enabled
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.10']
xpath: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.10']/prefix-length
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.10']
xpath: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.10']/prefix-length
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.15']
xpath: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.15']/prefix-length
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.15']
xpath: /ietf-interfaces:interfaces/interface[name='ens32']/ietf-ip:ipv4/address[ip='192.168.32.15']/prefix-length
xpath0: /ietf-interfaces:interfaces/interface[name='ens34']
xpath: /ietf-interfaces:interfaces/interface[name='ens34']/type, ianaift: iana-if-type:ethernetCsmacd
xpath: /ietf-interfaces:interfaces/interface[name='ens34']/enabled
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens34']/ietf-ip:ipv4/address[ip='192.168.34.15']
xpath: /ietf-interfaces:interfaces/interface[name='ens34']/ietf-ip:ipv4/address[ip='192.168.34.15']/prefix-length
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens34']/ietf-ip:ipv4/address[ip='192.168.34.15']
xpath: /ietf-interfaces:interfaces/interface[name='ens34']/ietf-ip:ipv4/address[ip='192.168.34.15']/prefix-length
xpath_ip: /ietf-interfaces:interfaces/interface[name='ens34']/ietf-ip:ipv4/address[ip='192.168.34.10']
xpath: /ietf-interfaces:interfaces/interface[name='ens34']/ietf-ip:ipv4/address[ip='192.168.34.10']/prefix-length
xpath0: /ietf-interfaces:interfaces/interface[name='lo']
xpath: /ietf-interfaces:interfaces/interface[name='lo']/type, ianaift: iana-if-type:softwareLoopback
xpath:/ietf-interfaces:interfaces/interface[name='lo']/enabled
xpath_ip: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']
xpath: /ietf-interfaces:interfaces/interface[name='lo']/ietf-ip:ipv4/address[ip='127.0.0.1']/prefix-length
[INF]: No datastore changes to apply.
sr_apply_changes end
可以看到两种方式得到的结果是相同的。
完毕!