0%

SONiC中交换芯片启动流程简述

写在前面

本文基于SONiC 202012分支进行交换芯片启动流程的分析。源码部分主要涉及sonic-swsssonic-sairedis以及ocp-sai. 一句话说明所有流程:swss模块通知syncd模块进行ASIC初始化。

模块主要功能说明

docker swss中的模块主要可以分为三类:

  1. 收集信息写往APP_DB,如portsyncd, intfsyncd(*syncd)
  2. 订阅APP_DB将数据写往ASIC_DB,如orchagent(是APP_DB的consumer,同时也是ASIC_DB的producer)
  3. 收集数据写往kernel, IntfMgrd和VlanMgrd

docker syncd中主要是syncd模块,该模块订阅ASIC_DB,之后调用sai api操作sdk, 完成数据的下发。

从swss开始

搞清楚ASIC的启动流程,实际上上就是弄清楚orchagent和syncd这两个进程的初始化和通信的过程。

在docker syncd的启动脚本中,我们可以看到其依赖关系。

docker swss中orchagent负责通知syncd进行ASIC初始化, 对于orchagent主要理解下面两行代码:

这里简要说明一下OCP SAI的工作方式,对应的源码在src/sonic-sairedis/SAI, 这里面定义了sai的data以及functions,还有一些metadata操作方式,而数据的初始化以及函数的实现由芯片厂商实现,通过动态库的方式提供。syncd编译时会链接到libsai,这样我们在syncd中就可以调用sai api完成对SDK的控制。

与此类似的,在sonic-sairedis中提供一个libsairedis的动态库(源码在src/sonic-sairedis/lib),这里面同样对ocp sai进行实现,不过实现的对象是redis,这样在orchagent中就可以调用sai api完成对redis的操作。

对于initSaiApi

对于sai_api_query, 在src/sonic-sairedis/SAI/inc/sai.h中是对其的定义,在src/sonic-sairedis/lib/src/sai_redis_interfacequery.cpp中是对其的实现。借用API宏完成对其初始化。

注意sai_apis_t结构体是src/sonic-sairedis/SAI/meta/parse.plperl脚本自动生成的,生成的文件名为saimetadata.h,结构体成员为各功能模块的结构体指针。

sai_switch_api为例:

到这里就完成了对OCP SAI的封装调用,而最后对redis的操作,201911之后的版本,实际的redis操作函数都使用宏来生成。

1
2
REDIS_GENERIC_QUAD
REDIS_CREATE

这部分操作的就是将create_switch的信息写到ASIC_DB, syncd进程收到发布的消息之后进行真正的SDK初始化操作。

create_switch分析

redis_create_switch函数由宏定义展开:

1
2
REDIS_GENERIC_QUAD(OT,ot)        sai_redis.h
REDIS_CREATE(OT,ot) sai_redis.h

redis_sai的定义如下:

1
2
3
4
5
std::shared_ptr<SaiInterface> redis_sai = std::make_shared<ClientServerSai>();    sai_redis_interfacequery.cpp

SaiInterface是父类, ClientServerSai是其子类
RemoteSaiInterface同样是SaiInterface子类
RedisRemoteSaiInterface又是RemoteSaiInterface的子类

redis_sai的指针类型是SaiInterface,根据C++的多态特性,redis_sai->create的最终实现在:

syncd初始化ASIC

直接从初始化sai api开始(由于201911之后的版本syncd模块重构了,变得更加难看,下面的分析基于201911版本,基本流程都差不多):

在mainloop里面进入processEvent流程,里面进入initviewmode:

之后:

然后调用sai api完成交换芯片初始化指令的下发:

最后就是sai模块中厂商对应的实现: