netopeer2 主要流程导读

[!note]
本篇文档的所有分析过程均基于如下软件版本:

概述

本篇文档主要介绍了 netopeer2 的主要流程和构造。

netopeer2 的主要架构已经在 官方文档 中描述得非常清楚,本文只是记录了对官方文档及源码的一些学习和思考过程。

主要流程

初始化

netopeer2 的 main 函数主要过程如下:

  1. 设置 singal handler(在接收到终止信号时通知各 worker 结束循环)
  2. 解析参数。参数介绍见 print_usage 函数
  3. 创建 pid 文件
  4. 设置 libnetconf2、libyang 和 sysrepo 的 log 回调
  5. 初始化 netconf 服务器(server_init),主要包括:
    1. 初始化 sysrepo 连接,此步骤消耗大量内存,内存量与 yang 模型总大小强相关
    2. 初始化 libnetconf2
  6. 订阅 sysrepo 事件(包括 rpc 和数据变更事件)
  7. 启动多个 worker 线程以监听并处理连接
  8. 主线程也作为一个 worker 开始工作

这里有个巧思,很多程序都会启动 worker_thread 作为业务处理线程,而启动后主线程就无事可做了,出于 idle 状态。而 netopeer2 在主线程也调用了 worker 函数,即它本身也作为一个 worker 线程,减少了创建一个线程的开销。

由于设置了 singal handler,当接收到终止信号时,各 worker 线程(包括主线程)会退出 worker 循环,不再监听连接。

主线程退出 worker 循环后,会等待所有 worker 线程退出并清理相关资源。

worker 线程

worker 线程是一个 loop 结构,其主体循环执行一系列操作以创建、跟踪并处理会话。其主体内容如子章节所述。

worker 线程通过一个原子变量 loop_continue 控制 是否继续进行循环,如果原子变量为 0,则结束循环并清理资源后退出。原子变量置 0 后 loop 退出的最长时间 约为 200ms。

创建新会话

在 worker_thread 的循环中,首先尝试接受一个新的 netconf session(会话)。会话指的是一个客户端到服务端的连接,netconf 使用 session 维持连接状态和上下文,并通过 sesssion 进行数据操作、事务管理、事件订阅等功能。

创建新 session 的功能由 server_accept_session 函数实现,其主要流程如下:

  1. 检查 是否存在监听中的 endpoint(例如 ssh、tld、unix socket 等,由 nc_server_add_endpt 添加)
    1. 如果不存在监听中的 endpoint,流程直接结束
  2. 从 sysrepo 连接中调用 sr_acquire_context 获取 libyang context
    1. 在这个过程中(sr_acquire_context -> sr_lycc_lock),sysrepo 会 检查 当前连接的 content_id 是否与 sysrepo main shm 中的 content_id 一致(即检查两者的内容版本是否一致)。
    2. 如果不一致,则重新加载新的 yang modules 作为新的 libyang context。
    3. 这一步主要是方式 sysrepo connection 创建之后 yang modules 由变动的情况
  3. 获取 ly_ctx 之后,netopeer2 调用 nc_accept 尝试获取一个会话(netconf session),其主要过程如下:
    1. 初始化 lyd_ctx
    2. 从监听的 endpoint 上尝试 获取 一个 socket 绑定
      1. 如果 有 endpoint 已经就绪(有新连接),则直接 accept 此 socket
      2. 否则,调用 poll 检查 所有 endpoint(其中timeout=0)
        1. 如果有已就绪的连接,则 accept 最后一个 就绪 endpoint 的 socket,其它 endpoint 设置为就绪状态
    3. 如果有新 socket 连接,则 创建 一个新会话,并使用 socket 信息初始化会话。初始化过程主要包括:
      1. 记录 socket 相关信息
      2. 根据 endpoint 类型,初始化 具体的连接(如 SSH 认证、建立连接等)
      3. 发送 netconf handshake 信息
  4. 如果成功创建一个正常的 session,则调用 np2srv_new_session_cb 初始化 netopeer2 callback 信息,包括:
    1. 将该 session 通过 ncm_session_add 加入 监控列表 stats.sessions 中
    2. 从 sysrepo connection 中 创建 一个 session 并 记录 到 netconf session 上。这一步的目的是让每个 netconf session 可以独立地利用 sysrepo session 进行消息订阅、上锁等操作
    3. 将新建的 session 通过 nc_ps_add_session 添加 到 netconf 会话池中以便跟踪
    4. 向 sysrepo 发送 netconf notification 通告 新连接已创立,并表达连接者的身份
  5. 经过上面的步骤后,新会话已完成连接、握手、初始化等环境,进入可用状态

会话处理

在 worker_thread 的每轮 loop 中,都会通过 调用 nc_ps_poll 处理现有的会话。会话的处理过程大致如下:

  1. 逐个 检查现有会话,通过 调用 nc_ps_poll_session_io 获取会话状态(是否有新消息、连接是否已经关闭……)
  2. 如果 存在已经有数据的会话,则通过 调用 nc_server_recv_rpc_io 从底层信道(SSH、TLS、unix socket)中 接收数据 并尝试 解析 为 netconf 消息
  3. 如果接收到的 netconf 消息合法无误,则通过 调用 nc_server_send_reply_io 完成消息处理并回复请求

其中,消息处理功能在 nc_server_send_reply_io 中实现。其大致流程如下:

  1. 从消息中 找到 操作类型对应的 lysc_node 节点
  2. 如果 lysc_node 节点没有指定自定义的 callback,则调用 global RPC callback(一般指向 np2srv_rpc_cb
    1. callback 中主要通过 调用 sr_rpc_send_tree 完成消息处理
  3. 否则,调用 lysc_node 节点自定义的 callback 处理消息
    1. 自定义 callback 消息目前只默认设置了这些回调:
      1. get-schema:指向 nc_clb_default_get_schema,获取结构信息
      2. close-session:指向 nc_clb_default_close_session,关闭会话
  4. 最后,将 callback 处理后的消息回复给客户端

会话处理过程在官方文档中亦有记述,如下图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

focksorCr

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值