Skip to content

Commit 1951365

Browse files
[vog/systemlag] Voq lagid allocator (#1603)
What I did Defined class for lag id allocator and added lua script for allocating/freeing lag id in atomic fashion Why I did it For portchannels in VOQ based chassis systems we need unique lag id across the system. The lag id (aka system port aggreggator id) is allocated during portchannel creation. The changes are for a class for lag id allocation in atomic fashion. The LAG ID is allocated from central chassis app db. A lua script loaded in the redis at the time of lag id allocator instantiation ensures allocating unique lag id when multiple clients requests for lag id simultaneously. Ref: VOQ LAG HLD PR: sonic-net/SONiC#697
1 parent b0c2a74 commit 1951365

3 files changed

Lines changed: 228 additions & 0 deletions

File tree

orchagent/lagid.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#include "lagid.h"
2+
3+
LagIdAllocator::LagIdAllocator(
4+
_In_ DBConnector* chassis_app_db)
5+
{
6+
SWSS_LOG_ENTER();
7+
8+
m_dbConnector = chassis_app_db;
9+
10+
// Load lua script to allocate system lag id. This lua script ensures allocation
11+
// of unique system lag id from global chassis app db in atomic fashion when allocation
12+
// is requested by different asic instances simultaneously
13+
14+
string luaScript = loadLuaScript("lagids.lua");
15+
m_shaLagId = loadRedisScript(m_dbConnector, luaScript);
16+
}
17+
18+
int32_t LagIdAllocator::lagIdAdd(
19+
_In_ const string &pcname,
20+
_In_ int32_t lag_id)
21+
{
22+
SWSS_LOG_ENTER();
23+
24+
// No keys
25+
vector<string> keys;
26+
27+
vector<string> args;
28+
args.push_back("add");
29+
args.push_back(pcname);
30+
args.push_back(to_string(lag_id));
31+
32+
set<string> ret = runRedisScript(*m_dbConnector, m_shaLagId, keys, args);
33+
34+
if (!ret.empty())
35+
{
36+
// We expect only one value in the set returned
37+
38+
auto rv_lag_id = ret.begin();
39+
40+
return (stoi(*rv_lag_id));
41+
}
42+
43+
return LAG_ID_ALLOCATOR_ERROR_DB_ERROR;
44+
}
45+
46+
int32_t LagIdAllocator::lagIdDel(
47+
_In_ const string &pcname)
48+
{
49+
SWSS_LOG_ENTER();
50+
51+
// No keys
52+
vector<string> keys;
53+
54+
vector<string> args;
55+
args.push_back("del");
56+
args.push_back(pcname);
57+
58+
set<string> ret = runRedisScript(*m_dbConnector, m_shaLagId, keys, args);
59+
60+
if (!ret.empty())
61+
{
62+
// We expect only one value in the set returned
63+
64+
auto rv_lag_id = ret.begin();
65+
66+
return (stoi(*rv_lag_id));
67+
}
68+
69+
return LAG_ID_ALLOCATOR_ERROR_DB_ERROR;
70+
}
71+
72+
int32_t LagIdAllocator::lagIdGet(
73+
_In_ const string &pcname)
74+
{
75+
SWSS_LOG_ENTER();
76+
77+
// No keys
78+
vector<string> keys;
79+
80+
vector<string> args;
81+
args.push_back("get");
82+
args.push_back(pcname);
83+
84+
set<string> ret = runRedisScript(*m_dbConnector, m_shaLagId, keys, args);
85+
86+
if (!ret.empty())
87+
{
88+
// We expect only one value in the set returned
89+
90+
auto rv_lag_id = ret.begin();
91+
92+
return (stoi(*rv_lag_id));
93+
}
94+
95+
return LAG_ID_ALLOCATOR_ERROR_DB_ERROR;
96+
}

orchagent/lagid.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef SWSS_LAGID_H
2+
#define SWSS_LAGID_H
3+
4+
#include "dbconnector.h"
5+
#include "sal.h"
6+
#include "schema.h"
7+
#include "redisapi.h"
8+
9+
using namespace swss;
10+
using namespace std;
11+
12+
#define LAG_ID_ALLOCATOR_ERROR_DELETE_ENTRY_NOT_FOUND 0
13+
#define LAG_ID_ALLOCATOR_ERROR_TABLE_FULL -1
14+
#define LAG_ID_ALLOCATOR_ERROR_GET_ENTRY_NOT_FOUND -2
15+
#define LAG_ID_ALLOCATOR_ERROR_INVALID_OP -3
16+
#define LAG_ID_ALLOCATOR_ERROR_DB_ERROR -4
17+
18+
class LagIdAllocator
19+
{
20+
public:
21+
22+
LagIdAllocator(
23+
_In_ DBConnector* chassis_app_db);
24+
25+
public:
26+
27+
int32_t lagIdAdd(
28+
_In_ const string &pcname,
29+
_In_ int32_t lag_id);
30+
31+
int32_t lagIdDel(
32+
_In_ const string &pcname);
33+
34+
int32_t lagIdGet(
35+
_In_ const string &pcname);
36+
37+
private:
38+
39+
DBConnector* m_dbConnector;
40+
41+
string m_shaLagId;
42+
};
43+
44+
#endif // SWSS_LAGID_H

orchagent/lagids.lua

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
-- KEYS - None
2+
-- ARGV[1] - operation (add/del/get)
3+
-- ARGV[2] - lag name
4+
-- ARGV[3] - current lag id (for "add" operation only)
5+
6+
-- return lagid if success for "add"/"del"
7+
-- return 0 if lag does not exist for "del"
8+
-- return -1 if lag table full for "add"
9+
-- return -2 if lag does not exist for "get"
10+
-- return -3 if invalid operation
11+
12+
local op = ARGV[1]
13+
local pcname = ARGV[2]
14+
15+
local lagid_start = tonumber(redis.call("get", "SYSTEM_LAG_ID_START"))
16+
local lagid_end = tonumber(redis.call("get", "SYSTEM_LAG_ID_END"))
17+
18+
if op == "add" then
19+
20+
local plagid = tonumber(ARGV[3])
21+
22+
local dblagid = redis.call("hget", "SYSTEM_LAG_ID_TABLE", pcname)
23+
24+
if dblagid then
25+
dblagid = tonumber(dblagid)
26+
if plagid == 0 then
27+
-- no lagid proposed. Return the existing lagid
28+
return dblagid
29+
end
30+
end
31+
32+
-- lagid allocation request with a lagid proposal
33+
if plagid >= lagid_start and plagid <= lagid_end then
34+
if plagid == dblagid then
35+
-- proposed lagid is same as the lagid in database
36+
return plagid
37+
end
38+
-- proposed lag id is different than that in database OR
39+
-- the portchannel does not exist in the database
40+
-- If proposed lagid is available, return the same proposed lag id
41+
if redis.call("sismember", "SYSTEM_LAG_ID_SET", tostring(plagid)) == 0 then
42+
redis.call("sadd", "SYSTEM_LAG_ID_SET", tostring(plagid))
43+
redis.call("srem", "SYSTEM_LAG_ID_SET", tostring(dblagid))
44+
redis.call("hset", "SYSTEM_LAG_ID_TABLE", pcname, tostring(plagid))
45+
return plagid
46+
end
47+
end
48+
49+
local lagid = lagid_start
50+
while lagid <= lagid_end do
51+
if redis.call("sismember", "SYSTEM_LAG_ID_SET", tostring(lagid)) == 0 then
52+
redis.call("sadd", "SYSTEM_LAG_ID_SET", tostring(lagid))
53+
redis.call("srem", "SYSTEM_LAG_ID_SET", tostring(dblagid))
54+
redis.call("hset", "SYSTEM_LAG_ID_TABLE", pcname, tostring(lagid))
55+
return lagid
56+
end
57+
lagid = lagid + 1
58+
end
59+
60+
return -1
61+
62+
end
63+
64+
if op == "del" then
65+
66+
if redis.call("hexists", "SYSTEM_LAG_ID_TABLE", pcname) == 1 then
67+
local lagid = redis.call("hget", "SYSTEM_LAG_ID_TABLE", pcname)
68+
redis.call("srem", "SYSTEM_LAG_ID_SET", lagid)
69+
redis.call("hdel", "SYSTEM_LAG_ID_TABLE", pcname)
70+
return tonumber(lagid)
71+
end
72+
73+
return 0
74+
75+
end
76+
77+
if op == "get" then
78+
79+
if redis.call("hexists", "SYSTEM_LAG_ID_TABLE", pcname) == 1 then
80+
local lagid = redis.call("hget", "SYSTEM_LAG_ID_TABLE", pcname)
81+
return tonumber(lagid)
82+
end
83+
84+
return -2
85+
86+
end
87+
88+
return -3

0 commit comments

Comments
 (0)