Skip to content

Commit

Permalink
[dbconnect]: Support DPU database schema (#845)
Browse files Browse the repository at this point in the history
This PR is for expanding the capability of dbconnect to adapt the new DPU DB schema introduced by PR: sonic-net/sonic-buildimage#17443
  • Loading branch information
Pterosaur committed Jan 27, 2024
1 parent e4db436 commit 41ee154
Show file tree
Hide file tree
Showing 10 changed files with 625 additions and 135 deletions.
278 changes: 183 additions & 95 deletions common/dbconnector.cpp

Large diffs are not rendered by default.

97 changes: 79 additions & 18 deletions common/dbconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
#include <map>
#include <memory>
#include <mutex>
#include <boost/functional/hash.hpp>
#include <boost/algorithm/string.hpp>

#include <hiredis/hiredis.h>
#include "rediscommand.h"
#include "redisreply.h"
#define EMPTY_NAMESPACE std::string()
#define EMPTY_CONTAINERNAME std::string()

namespace swss {

Expand All @@ -35,6 +38,52 @@ class SonicDBInfo
std::string separator;
};

struct SonicDBKey
{
/* Container name is used to identify the container that the DB instance is running in.
* Namespace is used to identify the network namespace that the DB instance is running in.
* In our design, we allow multiple containers to share a same namespace.
* So, this combination of container name and namespace is used to uniquely identify a DB instance.
* If the namespace is empty, it means the DB instance is running in the default(host) namespace.
* If the container name is empty, it for adapting the old design that only one DB instance is
* running in a namespace.
*/
std::string containerName;
std::string netns;

SonicDBKey() = default;
SonicDBKey(const std::string &ns) : netns(ns) {}

bool operator==(const SonicDBKey& other) const
{
return containerName == other.containerName && netns == other.netns;
}

bool isEmpty() const
{
return containerName.empty() && netns.empty();
}

std::string toString() const
{
std::vector<std::string> buffer;
buffer.push_back(containerName);
buffer.push_back(netns);
return boost::algorithm::join(buffer, ":");
}
};

struct SonicDBKeyHash
{
std::size_t operator()(const SonicDBKey& k) const
{
std::size_t seed = 0;
boost::hash_combine(seed, k.containerName);
boost::hash_combine(seed, k.netns);
return seed;
}
};

class SonicDBConfig
{
public:
Expand Down Expand Up @@ -62,14 +111,21 @@ class SonicDBConfig
static void reset();

static void validateNamespace(const std::string &netns);
static std::string getDbInst(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static int getDbId(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static std::string getSeparator(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static std::string getSeparator(int dbId, const std::string &netns = EMPTY_NAMESPACE);
static std::string getDbInst(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::string getDbInst(const std::string &dbName, const SonicDBKey &key);
static int getDbId(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static int getDbId(const std::string &dbName, const SonicDBKey &key);
static std::string getSeparator(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::string getSeparator(const std::string &dbName, const SonicDBKey &key);
static std::string getSeparator(int dbId, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::string getSeparator(int dbId, const SonicDBKey &key);
static std::string getSeparator(const DBConnector* db);
static std::string getDbSock(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static std::string getDbHostname(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static int getDbPort(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static std::string getDbSock(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::string getDbSock(const std::string &dbName, const SonicDBKey &key);
static std::string getDbHostname(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::string getDbHostname(const std::string &dbName, const SonicDBKey &key);
static int getDbPort(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static int getDbPort(const std::string &dbName, const SonicDBKey &key);
static std::vector<std::string> getNamespaces();
#if defined(SWIG) && defined(SWIGPYTHON)
%pythoncode %{
Expand All @@ -80,27 +136,29 @@ class SonicDBConfig
%}
#endif

static std::vector<std::string> getDbList(const std::string &netns = EMPTY_NAMESPACE);
static std::vector<std::string> getDbList(const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::vector<std::string> getDbList(const SonicDBKey &key);
static bool isInit() { return m_init; };
static bool isGlobalInit() { return m_global_init; };
static std::map<std::string, RedisInstInfo> getInstanceList(const std::string &netns = EMPTY_NAMESPACE);
static std::map<std::string, RedisInstInfo> getInstanceList(const std::string &netns = EMPTY_NAMESPACE, const std::string &containerName=EMPTY_CONTAINERNAME);
static std::map<std::string, RedisInstInfo> getInstanceList(const SonicDBKey &key);

private:
static std::recursive_mutex m_db_info_mutex;
// { namespace { instName, { unix_socket_path, hostname, port } } }
static std::unordered_map<std::string, std::map<std::string, RedisInstInfo>> m_inst_info;
// { namespace, { dbName, {instName, dbId, separator} } }
static std::unordered_map<std::string, std::unordered_map<std::string, SonicDBInfo>> m_db_info;
// { namespace, { dbId, separator } }
static std::unordered_map<std::string, std::unordered_map<int, std::string>> m_db_separator;
// { {containerName, namespace}, { instName, { unix_socket_path, hostname, port } } }
static std::unordered_map<SonicDBKey, std::map<std::string, RedisInstInfo>, SonicDBKeyHash> m_inst_info;
// { {containerName, namespace}, { dbName, {instName, dbId, separator} } }
static std::unordered_map<SonicDBKey, std::unordered_map<std::string, SonicDBInfo>, SonicDBKeyHash> m_db_info;
// { {containerName, namespace}, { dbId, separator } }
static std::unordered_map<SonicDBKey, std::unordered_map<int, std::string>, SonicDBKeyHash> m_db_separator;
static bool m_init;
static bool m_global_init;
static void parseDatabaseConfig(const std::string &file,
std::map<std::string, RedisInstInfo> &inst_entry,
std::unordered_map<std::string, SonicDBInfo> &db_entry,
std::unordered_map<int, std::string> &separator_entry);
static SonicDBInfo& getDbInfo(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static RedisInstInfo& getRedisInfo(const std::string &dbName, const std::string &netns = EMPTY_NAMESPACE);
static RedisInstInfo& getRedisInfo(const std::string &dbName, const SonicDBKey &key);
static SonicDBInfo& getDbInfo(const std::string &dbName, const SonicDBKey &key);
};

class RedisContext
Expand Down Expand Up @@ -158,6 +216,7 @@ class DBConnector : public RedisContext
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);
DBConnector(const std::string &dbName, unsigned int timeout, bool isTcpConn, const SonicDBKey &key);
DBConnector& operator=(const DBConnector&) = delete;

int getDbId() const;
Expand All @@ -169,6 +228,7 @@ class DBConnector : public RedisContext
namespace = property(getNamespace)
%}
#endif
SonicDBKey getDBKey() const;

static void select(DBConnector *db);

Expand Down Expand Up @@ -252,10 +312,11 @@ class DBConnector : public RedisContext
std::map<std::string, std::map<std::string, std::map<std::string, std::string>>> getall();
private:
void setNamespace(const std::string &netns);
void setDBKey(const SonicDBKey &key);

int m_dbId;
std::string m_dbName;
std::string m_namespace;
SonicDBKey m_key;
};

template <typename ReturnType>
Expand Down
1 change: 1 addition & 0 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ tests_tests_SOURCES = tests/redis_ut.cpp \
common/loglevel.cpp \
tests/loglevel_ut.cpp \
tests/redis_multi_ns_ut.cpp \
tests/redis_smartswitch_ut.cpp \
tests/fdb_flush.cpp \
tests/stringutility_ut.cpp \
tests/redisutility_ut.cpp \
Expand Down
3 changes: 2 additions & 1 deletion tests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ class SwsscommonEnvironment : public ::testing::Environment {
}
catch (exception &e)
{
EXPECT_TRUE(strstr(e.what(), "Namespace invalid is not a valid namespace name in config file"));
// EXPECT_TRUE(strstr(e.what(), "Key :invalid invalid is not a valid key name in config file"));
EXPECT_STREQ(e.what(), "Key :invalid is not a valid key name in config file");
}

// reset SonicDBConfig, init should be false
Expand Down
113 changes: 113 additions & 0 deletions tests/redis_multi_db_ut_config/database_config4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
{
"INSTANCES": {
"redis":{
"hostname" : "127.0.0.1",
"port": 6379,
"unix_socket_path": "/var/run/redis/redis.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"
},
"PROFILE_DB" : {
"id" : 12,
"separator": "|",
"instance" : "redis"
},
"STATE_DB2" : {
"id" : 13,
"separator": "|",
"instance" : "redis"
},
"APPL_STATE_DB" : {
"id" : 14,
"separator": ":",
"instance" : "redis"
},
"DPU_APPL_DB" : {
"id" : 15,
"separator": ":",
"instance" : "redis",
"format": "proto"
},
"DPU_APPL_STATE_DB" : {
"id" : 16,
"separator": "|",
"instance" : "redis"
},
"DPU_STATE_DB" : {
"id" : 17,
"separator": "|",
"instance" : "redis"
},
"DPU_COUNTERS_DB" : {
"id" : 18,
"separator": ":",
"instance" : "redis"
}
},
"VERSION" : "1.0"
}

0 comments on commit 41ee154

Please sign in to comment.