Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[vog/systemlag] Voq lagid allocator #1603

Merged
merged 3 commits into from
Mar 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions orchagent/lagid.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include "lagid.h"

LagIdAllocator::LagIdAllocator(
_In_ DBConnector* chassis_app_db)
{
SWSS_LOG_ENTER();

m_dbConnector = chassis_app_db;

// Load lua script to allocate system lag id. This lua script ensures allocation
// of unique system lag id from global chassis app db in atomic fashion when allocation
// is requested by different asic instances simultaneously

string luaScript = loadLuaScript("lagids.lua");
m_shaLagId = loadRedisScript(m_dbConnector, luaScript);
}

int32_t LagIdAllocator::lagIdAdd(
_In_ const string &pcname,
_In_ int32_t lag_id)
{
SWSS_LOG_ENTER();

// No keys
vector<string> keys;

vector<string> args;
args.push_back("add");
args.push_back(pcname);
args.push_back(to_string(lag_id));

set<string> ret = runRedisScript(*m_dbConnector, m_shaLagId, keys, args);

if (!ret.empty())
{
// We expect only one value in the set returned

auto rv_lag_id = ret.begin();

return (stoi(*rv_lag_id));
}

return LAG_ID_ALLOCATOR_ERROR_DB_ERROR;
}

int32_t LagIdAllocator::lagIdDel(
_In_ const string &pcname)
{
SWSS_LOG_ENTER();

// No keys
vector<string> keys;

vector<string> args;
args.push_back("del");
args.push_back(pcname);

set<string> ret = runRedisScript(*m_dbConnector, m_shaLagId, keys, args);

if (!ret.empty())
{
// We expect only one value in the set returned

auto rv_lag_id = ret.begin();

return (stoi(*rv_lag_id));
}

return LAG_ID_ALLOCATOR_ERROR_DB_ERROR;
}

int32_t LagIdAllocator::lagIdGet(
_In_ const string &pcname)
{
SWSS_LOG_ENTER();

// No keys
vector<string> keys;

vector<string> args;
args.push_back("get");
args.push_back(pcname);

set<string> ret = runRedisScript(*m_dbConnector, m_shaLagId, keys, args);

if (!ret.empty())
{
// We expect only one value in the set returned

auto rv_lag_id = ret.begin();

return (stoi(*rv_lag_id));
}

return LAG_ID_ALLOCATOR_ERROR_DB_ERROR;
}
44 changes: 44 additions & 0 deletions orchagent/lagid.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef SWSS_LAGID_H
#define SWSS_LAGID_H

#include "dbconnector.h"
#include "sal.h"
#include "schema.h"
#include "redisapi.h"

using namespace swss;
using namespace std;

#define LAG_ID_ALLOCATOR_ERROR_DELETE_ENTRY_NOT_FOUND 0
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
#define LAG_ID_ALLOCATOR_ERROR_TABLE_FULL -1
#define LAG_ID_ALLOCATOR_ERROR_GET_ENTRY_NOT_FOUND -2
#define LAG_ID_ALLOCATOR_ERROR_INVALID_OP -3
#define LAG_ID_ALLOCATOR_ERROR_DB_ERROR -4

class LagIdAllocator
{
public:

LagIdAllocator(
_In_ DBConnector* chassis_app_db);

public:

int32_t lagIdAdd(
_In_ const string &pcname,
_In_ int32_t lag_id);

int32_t lagIdDel(
_In_ const string &pcname);

int32_t lagIdGet(
_In_ const string &pcname);

private:

DBConnector* m_dbConnector;

string m_shaLagId;
};

#endif // SWSS_LAGID_H
88 changes: 88 additions & 0 deletions orchagent/lagids.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
-- KEYS - None
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
-- ARGV[1] - operation (add/del/get)
-- ARGV[2] - lag name
-- ARGV[3] - current lag id (for "add" operation only)

-- return lagid if success for "add"/"del"
-- return 0 if lag does not exist for "del"
-- return -1 if lag table full for "add"
-- return -2 if lag does not exist for "get"
-- return -3 if invalid operation

local op = ARGV[1]
local pcname = ARGV[2]

local lagid_start = tonumber(redis.call("get", "SYSTEM_LAG_ID_START"))
local lagid_end = tonumber(redis.call("get", "SYSTEM_LAG_ID_END"))

if op == "add" then

local plagid = tonumber(ARGV[3])

local dblagid = redis.call("hget", "SYSTEM_LAG_ID_TABLE", pcname)

if dblagid then
dblagid = tonumber(dblagid)
if plagid == 0 then
-- no lagid proposed. Return the existing lagid
return dblagid
end
end

-- lagid allocation request with a lagid proposal
if plagid >= lagid_start and plagid <= lagid_end then
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
if plagid == dblagid then
-- proposed lagid is same as the lagid in database
return plagid
end
-- proposed lag id is different than that in database OR
-- the portchannel does not exist in the database
-- If proposed lagid is available, return the same proposed lag id
if redis.call("sismember", "SYSTEM_LAG_ID_SET", tostring(plagid)) == 0 then
redis.call("sadd", "SYSTEM_LAG_ID_SET", tostring(plagid))
redis.call("srem", "SYSTEM_LAG_ID_SET", tostring(dblagid))
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
redis.call("hset", "SYSTEM_LAG_ID_TABLE", pcname, tostring(plagid))
return plagid
end
end

local lagid = lagid_start
while lagid <= lagid_end do
if redis.call("sismember", "SYSTEM_LAG_ID_SET", tostring(lagid)) == 0 then
redis.call("sadd", "SYSTEM_LAG_ID_SET", tostring(lagid))
redis.call("srem", "SYSTEM_LAG_ID_SET", tostring(dblagid))
redis.call("hset", "SYSTEM_LAG_ID_TABLE", pcname, tostring(lagid))
return lagid
end
lagid = lagid + 1
end

return -1

end

if op == "del" then

if redis.call("hexists", "SYSTEM_LAG_ID_TABLE", pcname) == 1 then
local lagid = redis.call("hget", "SYSTEM_LAG_ID_TABLE", pcname)
redis.call("srem", "SYSTEM_LAG_ID_SET", lagid)
redis.call("hdel", "SYSTEM_LAG_ID_TABLE", pcname)
return tonumber(lagid)
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
end

return 0

end

if op == "get" then

if redis.call("hexists", "SYSTEM_LAG_ID_TABLE", pcname) == 1 then
local lagid = redis.call("hget", "SYSTEM_LAG_ID_TABLE", pcname)
return tonumber(lagid)
judyjoseph marked this conversation as resolved.
Show resolved Hide resolved
end

return -2

end

return -3