SONiC内部通信机制

SONiC使用了发布订阅机制与redis的键空间通知机制(当客户端修改数据时,redis服务器会通知其他相关订阅者(client)的数据变化)。

数据库角色

SONiC 中使用到的数据库如下:

  • 0号数据库:APPL_DB,存储所有应用程序生成的状态——路由、下一跳、邻居等。这是应用程序与其他SONiC子系统交互的入口点;
  • 1号数据库:ASIC_DB,存放底层 ASIC 的状态信息和配置表项,格式对底层芯片友好,芯片重启可以从ASIC_DB快速恢复;
  • 2号数据库:CONTERS_DB,存放每个端口计数器和统计信息,这些信息可以被cli使用或者反馈给telemetry;
  • 3号数据库:LOGLEVEL_DB,存放日志配置等级信息;
  • 4号数据库:CONFIG_DB,存储SONiC应用程序创建的配置状态——端口配置、接口、VLAN等,有的APP/模块可能没有配置,可以没有对应表,有的配置直接调用linux的命令进行配置,有的配置还需要下发到芯片,这时需要往APPL_DB里写;
  • 5号数据库:FLEX_COUNTER_DB,存放灵活计数器配置;
  • 6号数据库:STATE_DB,存储系统中配置实体的“关键”操作状态。此状态用于解决不同SONiC子系统之间的依赖关系。例如,LAG端口channel(由teamd子模块定义)可能指系统中可能存在或不存在的物理端口。另一个例子是VLAN的定义(通过vlanmgrd组件),它可能引用系统中存在未知的端口成员。本质上,该数据库存储了解决跨模块依赖关系所需的所有状态。

image.png

SubscriberStateTable

在SONiC中,CONFIG_DB和STATE_DB之间的数据监听通过 key-space 机制实现。key-space 机制的消费者通过 sonic-swss-common/common 中的 SubscriberStateTable 类实现。

对CONFIG_DB的修改一般用于对系统进行配置操作,如使用命令行来配置系统功能,SONiC在sonic-py-swsssdk组件中封装了对CONFIG_DB的操作,根据传递data是否为空执行hmset或delete操作。

这里以监听CONFIG_DB配置VLAN为例说明。

VlanMgr 组件在初始化时监听CFG_VLAN_TABLE_NAMECFG_VLAN_MEMBER_TABLE_NAME两个 key-space 事件,当通过config命令(sonic cli)添加 vlan 100的操作时,redis服务器的 CONFIG_DB 会为“VLAN|Vlan100”的KEY产生 key-space事件消息, VlanMgr 组件收到后,调用 VlanMgr::doTask(Consumer &consumer) 处理。

@startuml

config -> redis服务器 : 写redis
redis服务器 -> client : 产生keyspace消息 
client -> client : 接收消息,并调用函数处理

@enduml

G23164.png

收到消息后,这里的Consumer即是通过orch类封装过的 SubscriberStateTable 。

NotificationProducer/Consumer

通过消息队列来传递信息,内容可以灵活定义。在 SONiC 中,该通信模型主要用于 SWSS容器中的 orchagent 与 syncd 容器中的之间的事件通知。

以FDB事件为例,SYNCD收到来自底层驱动的FDB事件,调用对数据库的hset或del操作更新ASIC_DB中的FDB表项,同时作为Notification生产者发送名为“fdb_event”的通知消息。
Notification的消费者流程在fdborch中实现,通知消息触发FdbOrch::doTask(NotificationConsumer&consumer)来进行后续处理,更新orchagent中的FDB信息。

Producer/ConsumerStateTable

sonic-swss-common 中 ProducerStateTable 与 ConsumerStateTable 实现

该机制通过一个set集合传递key,通过publish命令通知有新的key产生。消费者通过key组合成一个hash表的key,用于获取真实的消息,set不保证顺序,在publish通知KEY修改事件前允许对key-value进行多次操作,操作过程不保证执行顺序。这样做的好处是不必在每次设置key-value时都触发事件通知,可以提升处理效率,但对orchagent处理流程有一定要求。

示例:

## 在集合INTF_TABLE_KEY_SET中增加一个key
"SADD" "INTF_TABLE_KEY_SET" "PortChannel1:1.1.1.1/8"

## 在hash表INTF_TABLE:PortChannel1:1.1.1.1/8中添加内容
"HSET" "INTF_TABLE:PortChannel1:1.1.1.1/8" "scope" "global" 
"HSET" "INTF_TABLE:PortChannel1:1.1.1.1/8" "family" "IPv4"

## 通知订阅者频道 INTF_TABLE_CHANNEL 有消息,订阅者根据 INTF_TABLE_组合成 INTF_TABLE_KEY_SET 获取key,
## 然后,根据key获取hash表 INTF_TABLE:PortChannel1:1.1.1.1/8 的内容,如果该内容为空则表示删除操作,否则表示SET操作。
"PUBLISH" "INTF_TABLE_CHANNEL" "G"    

Orchagent调度处理采用epoll事件通知模型,事件触发即会产生调度;在调度处理中,可能出现因资源依赖等因素导致任务处理无法完成,此时可以选择将任务保留在m_toSync中等待下一次调度处理。在大规模控制表项和较复杂逻辑关系的场景下,这种调度机制可能出现因资源限制、依赖条件不满足等因素导致的频繁或无效调度,Asterfusion通过优化处理顺序、改进批量操作以及在STATE_DB中设置状态标志等改进方式,提高了组件运行效率并增强了可靠性。

ProducerTable & ConsumerTable

使用redis publish 通知KEY修改事件,利用Key-Value-Operate机制来传递信息。该通信模型通过有序链表(list)来传递key-value-operate三元消息,一次操作在LIST中压入三个值(通知订阅者进行消息处理,循环处理消息,一次必须从链表中拿出三个key),分别为key,value,operate。其中的 value 是把一个 hash表进行json编码后形成了一个单一的字符串,所以订阅者得到消息后需要进行解码还原,最后一个是操作类型。

SYNCD 通过这种方式List队列获得 key-value-operation, 然后解码,写入到ASIC_STATE,同时调用底层SAI接口。

在SONiC中,该模型用于围绕ASIC_DB和FLEX_COUNTER_DB的消息传递。与模型3相比,该模型保证了操作的严格执行顺序,在 syncd 执行 SAI API 调用时保证了对底层ASIC的操作时序。

示例:

"LPUSH" "ASIC_STATE_KEY_VALUE_OP_QUEUE" "SAI_OBJECT_TYPE_ROUTE_ENTRY:{\"dest\":\"1.1.1.0/24\",\"switch_id\":\"oid:0x21000000000000\",\"table_id\":\"oid:0x0\",\"vr\":\"oid:0x3000000000043\"}" "[\"SAI_ROUTE_ENTRY_ATTR_PACKET_ACTION\",\"SAI_PACKET_ACTION_FORWARD\",\"SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID\",\"oid:0x600000000063a\"]" "Screate"

## 通知订阅者进行消息处理,循环处理消息,一次必须从链表中拿出三个key
"PUBLISH" "ASIC_STATE_CHANNEL" "G"  

与内核的通信方式

网络接口事件和路由等需要SONiC应用程序与Linux内核通信,主要通过两种方式:

  • 调用Linux工具命令, 如调用ip命令配置网络接口IP地址和设置VRF,又如调用bridge命令配置VLAN。用封装的swss::exec方法最终通过popen执行拼装好的command指令。
  • 对netlink消息操作则是通过以libnl库为基础封装的NetLink类来完成,同时SWSS也定义了一套NetDispatcher机制来实现netlink消息监听和分发处理。

nfvschool 微信公共号: nfvschool
nfvschool网址: nfvschool.cn

参考

Was this helpful?

2 / 0

发表回复 0