sonic中syncd容器与redis容器通信源码解析

摘要

整个功能实现基本由以下步骤组成

1.syncd初始化配置

2.连接数据库并监听

3.数据处理

背景

sonic-buildimage的git commit为774778,将在此版本上进行分析,github地址如下:

https://github.com/Azure/sonic-buildimage/tree/77477857b47b114fde18afc33985e1a76c464c09

进入src目录,可以看到对应的代码如下图:

用到的代码为sairedis(在syncd上容器运行,负责与redis数据库通信以及调用厂家提供的api及sdk,编译后的可执行文件名字为syncd)与swss-common,swss以后有机会的话再讲吧。

saireids地址:Azure/sonic-sairedis at 13474d17435d3876e7bd6b50133d25bb11dd3c54 (github.com)

在sonic中,database容器中运行的是redis数据库,而在syncd容器中使用了hiredis(redis数据库的c接口)与redis进行通信,hiredis的github地址如下:

https://github.com/search?q=hiredis

1.m_contextConfig初始化

在sonic-sairedis\syncd\Syncd.cpp的syncd构造函数中调用了如下函数,对容器的上下文进行初始化:

auto ccc = sairedis::ContextConfigContainer::loadFromFile(m_commandLineOptions->m_contextConfig.c_str());

m_contextConfig = ccc->get(m_commandLineOptions->m_globalContext);

m_commandLineOptions->m_contextConfig.c_str()是启动syncd时指定的命令行参数,如果不指定,将使用默认配置,代码不展开,直接给出默认情况下一些关键变量的值,若有兴趣可自行查看代码

class ContextConfigm_contextConfig
uint32_t m_guid0
std::string m_name"syncd"
std::string m_dbAsic"ASIC_DB"
std::string m_dbCounters"COUNTERS_DB"
std::string m_dbFlex"FLEX_COUNTER_DB"
std::string m_dbState"STATE_DB"
bool m_zmqEnableFALSE

2.连接redis,切换到指定数据库

m_dbAsic = std::make_shared<swss::DBConnector>(m_contextConfig->m_dbAsic, 0);

调用swss::DBConnector的构造函数,该 class 定义如下:

explicit DBConnector(const DBConnector &other);
DBConnector(int dbId, const RedisContext &ctx);
DBConnector(int dbId, const std::string &hostname, int port, unsigned int timeout);
DBConnector(int dbId, const std::string &unixPath, unsigned int timeout);
DBConnector(const std::string &dbName, unsigned int timeout, bool isTcpConn = false);
DBConnector(const std::string &dbName, unsigned int timeout, bool isTcpConn, const std::string &netns);

可以看到,这是一个多态的构造函数,根据传参可知,调用了第三个构造函数,并且bool isTcpConn = false。代码如下:

#define EMPTY_NAMESPACE std::string()//在别处定义

DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn, const string& netns)
    : m_dbId(SonicDBConfig::getDbId(dbName, netns))
    , m_dbName(dbName)
    , m_namespace(netns)
{
    struct timeval tv = {0, (suseconds_t)timeout * 1000};
    struct timeval *ptv = timeout ? &tv : NULL;
    if (isTcpConn)
    {
        initContext(SonicDBConfig::getDbHostname(dbName, netns).c_str(), SonicDBConfig::getDbPort(dbName, netns), ptv);
    }
    else
    {
        initContext(SonicDBConfig::getDbSock(dbName, netns).c_str(), ptv);
    }

    select(this);
}

DBConnector::DBConnector(const string& dbName, unsigned int timeout, bool isTcpConn)
    : DBConnector(dbName, timeout, isTcpConn, EMPTY_NAMESPACE)
{
    // Empty constructor
}

timeout为0,所以*ptv为NULL。

由于isTcpConn = false,所以执行else分支下的代码。先来看下initContext函数:

void RedisContext::initContext(const char *path, const timeval *tv)
{
    if (tv)
    {
        m_conn = redisConnectUnixWithTimeout(path, *tv);
    }
    else
    {
        m_conn = redisConnectUnix(path);
    }

    if (m_conn->err)
        throw system_error(make_error_code(errc::address_not_available),
                           "Unable to connect to redis (unix-socket)");
}

redisConnectUnix(path)为hiredis提供的api,用以连接redis,*path为SonicDBConfig::getDbSock(dbName, netns).c_str(),dbname为"ASIC_DB",netns为空字符串。

看一下getDbSock,代码如下:

string SonicDBConfig::getDbSock(const string &dbName, const string &netns)
{
    return getRedisInfo(dbName, netns).unixSocketPath;
}

RedisInstInfo& SonicDBConfig::getRedisInfo(const std::string &dbName, const std::string &netns)
{
    std::lock_guard<std::recursive_mutex> guard(m_db_info_mutex);

    SWSS_LOG_ENTER();

    if (!m_init)//值为false
        initialize(DEFAULT_SONIC_DB_CONFIG_FILE);

//余下部分省略
}

DEFAULT_SONIC_DB_CONFIG_FILE为宏定义,值在SonicDBConfig类中定义:

static constexpr const char *DEFAULT_SONIC_DB_CONFIG_FILE = "/var/run/
redis/sonic-db/database_config.json";

该路径是sonic系统中的路径,编译过程出会将sonic-swss-common\common\database_config.json放入sonic系统下的/var/run/
redis下,文件如下:

{
    "INSTANCES": {
        "redis":{
            "hostname" : "127.0.0.1",
            "port" : 6379,
            "unix_socket_path" : "/var/run/redis/redis.sock"
        },
        "redis_chassis":{
            "hostname" : "redis_chassis.server",
            "port" : 6380,
            "unix_socket_path" : "/var/run/redis/redis_chassis.sock"
        }
    },
    "DATABASES" : {
        "APPL_DB" : {
            "id" : 0,
            "separator": ":",
            "instance" : "redis"
        },
        "ASIC_DB" : {
            "id" : 1,
            "separator": ":",
            "instance" : "redis"
        },
        "COUNTERS_DB" : {
            "id" : 2,
            "separator": ":",
            "instance" : "redis"
        },
        "LOGLEVEL_DB" : {
            "id" : 3,
            "separator": ":",
            "instance" : "redis"
        },
        "CONFIG_DB" : {
            "id" : 4,
            "separator": "|",
            "instance" : "redis"
        },
        "PFC_WD_DB" : {
            "id" : 5,
            "separator": ":",
            "instance" : "redis"
        },
        "FLEX_COUNTER_DB" : {
            "id" : 5,
            "separator": ":",
            "instance" : "redis"
        },
        "STATE_DB" : {
            "id" : 6,
            "separator": "|",
            "instance" : "redis"
        },
        "SNMP_OVERLAY_DB" : {
            "id" : 7,
            "separator": "|",
            "instance" : "redis"
        },
        "RESTAPI_DB" : {
            "id" : 8,
            "separator": "|",
            "instance" : "redis"
        },
        "GB_ASIC_DB" : {
            "id" : 9,
            "separator": "|",
            "instance" : "redis"
        },
        "GB_COUNTERS_DB" : {
            "id" : 10,
            "separator": "|",
            "instance" : "redis"
        },
        "GB_FLEX_COUNTER_DB" : {
            "id" : 11,
            "separator": "|",
            "instance" : "redis"
        },
        "CHASSIS_APP_DB" : {
            "id" : 12,
            "separator": "|",
            "instance" : "redis_chassis"
        },
        "CHASSIS_STATE_DB" : {
            "id" : 13,
            "separator": "|",
            "instance" : "redis_chassis"
        }
    },
    "VERSION" : "1.0"
}

综上所述,initContext函数连接了/var/run/redis/redis.sock,接下来看select(this),代码如下

void DBConnector::select(DBConnector *db)
{
    string select("SELECT ");
    select += to_string(db->getDbId());

    RedisReply r(db, select, REDIS_REPLY_STATUS);
    r.checkStatusOK();
}

顾名思义,改函数执行了redis命令中的SELECT命令,切换到ASIC数据库。RedisReply封装了hiredis中的api,此处不展开。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
SONIC redis命令是指在SONiC操作系统使用Redis数据库进行管理和配置的命令。在SONiC,SAI Redis提供了一个基于Redis数据库的SAI Redis服务,它包含将SAI对象放入Redis数据库的SAI库和将SAI对象放入ASIC的同步对象两个主要组件。在执行SONIC redis命令时,通常会使用一些基本的Redis命令,比如SELECT命令用于切换到ASIC数据库[3]。关于SONIC redis命令的详细信息,你可以在SONiC的GitHub页面上找到更多的资料。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span> #### 引用[.reference_title] - *1* *3* *4* [sonicsyncd容器redis容器通信源码解析](https://blog.csdn.net/weixin_54558665/article/details/118249932)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [sonic-sairedis:到SONiC项目使用的Redis数据库的SAI对象接口](https://download.csdn.net/download/weixin_42135462/15251289)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值