Skip to content

Commit e193e9d

Browse files
authored
Make sairedis/syncd synchronous (#476)
* Make sairedis/syncd synchronous * Add wait for response for bulk api * Update aspell * Address comments * Add support for bulk route create in saiplayer * Fix spelling * Make synchronous mode optional and disabled by default
1 parent bd33da9 commit e193e9d

11 files changed

Lines changed: 236 additions & 15 deletions

lib/inc/sai_redis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,16 @@ extern void recordLine(std::string s);
5454
extern std::string joinFieldValues(
5555
_In_ const std::vector<swss::FieldValueTuple> &values);
5656

57+
extern sai_status_t internal_api_wait_for_response(
58+
_In_ sai_common_api_t api);
59+
5760
// other global declarations
5861

5962
extern volatile bool g_record;
6063
extern volatile bool g_useTempView;
6164
extern volatile bool g_asicInitViewMode;
6265
extern volatile bool g_logrotate;
66+
extern volatile bool g_syncMode;
6367

6468
extern sai_service_method_table_t g_services;
6569
extern std::shared_ptr<swss::ProducerTable> g_asicState;

lib/inc/sairedis.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ typedef enum _sai_redis_switch_attr_t
104104
*/
105105
SAI_REDIS_SWITCH_ATTR_PERFORM_LOG_ROTATE,
106106

107+
/**
108+
* @brief Synchronous mode.
109+
*
110+
* Enable or disable synchronous mode. When enabled syncd also needs to be
111+
* running in synchronous mode. Command pipeline will be disabled when this
112+
* flag will be set to true.
113+
*
114+
* @type bool
115+
* @flags CREATE_AND_SET
116+
* @default false
117+
*/
118+
SAI_REDIS_SWITCH_ATTR_SYNC_MODE,
119+
107120
} sai_redis_switch_attr_t;
108121

109122
/*

lib/src/sai_redis_generic_create.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,7 @@ sai_status_t internal_redis_generic_create(
234234

235235
g_asicState->set(key, entry, "create");
236236

237-
// we assume create will always succeed which may not be true
238-
// we should make this synchronous call
239-
return SAI_STATUS_SUCCESS;
237+
return internal_api_wait_for_response(SAI_COMMON_API_CREATE);
240238
}
241239

242240
sai_status_t redis_generic_create(
@@ -389,7 +387,7 @@ sai_status_t internal_redis_bulk_generic_create(
389387
g_asicState->set(key, entries, "bulkcreate");
390388
}
391389

392-
return SAI_STATUS_SUCCESS;
390+
return internal_api_wait_for_response(SAI_COMMON_API_CREATE);
393391
}
394392

395393
#define REDIS_ENTRY_CREATE(OT,ot) \

lib/src/sai_redis_generic_get.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ sai_status_t internal_redis_generic_get(
205205
const std::string &op = kfvOp(kco);
206206
const std::string &opkey = kfvKey(kco);
207207

208-
SWSS_LOG_DEBUG("response: op = %s, key = %s", opkey.c_str(), op.c_str());
208+
SWSS_LOG_INFO("response: op = %s, key = %s", opkey.c_str(), op.c_str());
209209

210210
if (op != "getresponse") // ignore non response messages
211211
{

lib/src/sai_redis_generic_remove.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ sai_status_t internal_redis_generic_remove(
2121

2222
g_asicState->del(key, "remove");
2323

24-
return SAI_STATUS_SUCCESS;
24+
return internal_api_wait_for_response(SAI_COMMON_API_REMOVE);
2525
}
2626

2727
sai_status_t redis_generic_remove(
@@ -118,10 +118,10 @@ sai_status_t internal_redis_bulk_generic_remove(
118118
}
119119

120120
/*
121-
* Capital 'C' stands for bulk CREATE operation.
121+
* Capital 'R' stands for bulk CREATE operation.
122122
*/
123123

124-
recordLine("C|" + str_object_type + joined);
124+
recordLine("R|" + str_object_type + joined);
125125
}
126126

127127
// key: object_type:count
@@ -134,7 +134,7 @@ sai_status_t internal_redis_bulk_generic_remove(
134134
g_asicState->set(key, entries, "bulkremove");
135135
}
136136

137-
return SAI_STATUS_SUCCESS;
137+
return internal_api_wait_for_response(SAI_COMMON_API_CREATE);
138138
}
139139

140140

lib/src/sai_redis_generic_set.cpp

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,83 @@
22
#include "meta/sai_serialize.h"
33
#include "meta/saiattributelist.h"
44

5+
sai_status_t internal_api_wait_for_response(
6+
_In_ sai_common_api_t api)
7+
{
8+
SWSS_LOG_ENTER();
9+
10+
if (!g_syncMode)
11+
{
12+
/*
13+
* By default sync mode is disabled and all create/set/remove are
14+
* considered success operations.
15+
*/
16+
17+
return SAI_STATUS_SUCCESS;
18+
}
19+
20+
SWSS_LOG_INFO("waiting for response %d", api);
21+
22+
swss::Select s;
23+
24+
s.addSelectable(g_redisGetConsumer.get());
25+
26+
while (true)
27+
{
28+
SWSS_LOG_INFO("wait for %d api response", api);
29+
30+
swss::Selectable *sel;
31+
32+
// get timeout and selector is used for all quad api's
33+
int result = s.select(&sel, GET_RESPONSE_TIMEOUT);
34+
35+
if (result == swss::Select::OBJECT)
36+
{
37+
swss::KeyOpFieldsValuesTuple kco;
38+
39+
g_redisGetConsumer->pop(kco);
40+
41+
const std::string &op = kfvOp(kco);
42+
const std::string &opkey = kfvKey(kco);
43+
44+
SWSS_LOG_INFO("response: op = %s, key = %s", opkey.c_str(), op.c_str());
45+
46+
if (op != "getresponse") // ignore non response messages
47+
{
48+
continue;
49+
}
50+
51+
sai_status_t status;
52+
sai_deserialize_status(opkey, status);
53+
54+
if (g_record)
55+
{
56+
const std::string &str_status = kfvKey(kco);
57+
const std::vector<swss::FieldValueTuple> &values = kfvFieldsValues(kco);
58+
59+
// first serialized is status
60+
recordLine("G|" + str_status + "|" + joinFieldValues(values));
61+
}
62+
63+
SWSS_LOG_DEBUG("generic %d api status: %d", api, status);
64+
65+
return status;
66+
}
67+
68+
SWSS_LOG_ERROR("generic %d api failed due to SELECT operation result: %s", api, getSelectResultAsString(result).c_str());
69+
break;
70+
}
71+
72+
if (g_record)
73+
{
74+
recordLine("G|SAI_STATUS_FAILURE");
75+
}
76+
77+
SWSS_LOG_ERROR("generic %d api failed to get response", api);
78+
79+
return SAI_STATUS_FAILURE;
80+
}
81+
582
sai_status_t internal_redis_generic_set(
683
_In_ sai_object_type_t object_type,
784
_In_ const std::string &serialized_object_id,
@@ -28,7 +105,7 @@ sai_status_t internal_redis_generic_set(
28105

29106
g_asicState->set(key, entry, "set");
30107

31-
return SAI_STATUS_SUCCESS;
108+
return internal_api_wait_for_response(SAI_COMMON_API_SET);
32109
}
33110

34111
sai_status_t internal_redis_bulk_generic_set(
@@ -110,7 +187,7 @@ sai_status_t internal_redis_bulk_generic_set(
110187
g_asicState->set(key, entries, "bulkset");
111188
}
112189

113-
return SAI_STATUS_SUCCESS;
190+
return internal_api_wait_for_response(SAI_COMMON_API_CREATE);
114191
}
115192

116193

lib/src/sai_redis_interfacequery.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ sai_status_t sai_api_initialize(
124124
g_redisNotifications = std::make_shared<swss::NotificationConsumer>(g_dbNtf.get(), "NOTIFICATIONS");
125125
g_redisClient = std::make_shared<swss::RedisClient>(g_db.get());
126126

127+
g_asicState->setBuffered(false); // in sync mode, always false
128+
127129
clear_local_state();
128130

129131
g_asicInitViewMode = false;

lib/src/sai_redis_switch.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
volatile bool g_asicInitViewMode = false; // default mode is apply mode
99
volatile bool g_useTempView = false;
10+
volatile bool g_syncMode = false;
1011

1112
sai_status_t sai_redis_internal_notify_syncd(
1213
_In_ const std::string& key)
@@ -266,7 +267,26 @@ sai_status_t redis_set_switch_attribute(
266267
g_useTempView = attr->value.booldata;
267268
return SAI_STATUS_SUCCESS;
268269

270+
case SAI_REDIS_SWITCH_ATTR_SYNC_MODE:
271+
272+
g_syncMode = attr->value.booldata;
273+
274+
if (g_syncMode)
275+
{
276+
SWSS_LOG_NOTICE("disabling buffered pipeline in sync mode");
277+
g_asicState->setBuffered(false);
278+
}
279+
280+
return SAI_STATUS_SUCCESS;
281+
269282
case SAI_REDIS_SWITCH_ATTR_USE_PIPELINE:
283+
284+
if (g_syncMode)
285+
{
286+
SWSS_LOG_WARN("use pipeline is not supported in sync mode");
287+
return SAI_STATUS_NOT_SUPPORTED;
288+
}
289+
270290
g_asicState->setBuffered(attr->value.booldata);
271291
return SAI_STATUS_SUCCESS;
272292

saiplayer/saiplayer.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,54 @@ sai_status_t handle_bulk_route(
964964

965965
return status;
966966
}
967+
else if (api == (sai_common_api_t)SAI_COMMON_API_BULK_CREATE)
968+
{
969+
std::vector<uint32_t> attr_count;
970+
971+
std::vector<const sai_attribute_t*> attr_list;
972+
973+
// route can have multiple attributes, so we need to handle them all
974+
for (const auto &alist: attributes)
975+
{
976+
attr_list.push_back(alist->get_attr_list());
977+
attr_count.push_back(alist->get_attr_count());
978+
}
979+
980+
SWSS_LOG_NOTICE("executing BULK route create with %zu routes", attr_count.size());
981+
982+
sai_status_t status = sai_bulk_create_route_entry(
983+
(uint32_t)routes.size(),
984+
routes.data(),
985+
attr_count.data(),
986+
attr_list.data(),
987+
SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, // TODO we need to get that from recording
988+
statuses.data());
989+
990+
if (status != SAI_STATUS_SUCCESS)
991+
{
992+
// Entire API fails, so no need to compare statuses.
993+
return status;
994+
}
995+
996+
for (size_t i = 0; i < statuses.size(); ++i)
997+
{
998+
if (statuses[i] != recorded_statuses[i])
999+
{
1000+
/*
1001+
* If recorded statuses are different than received, throw
1002+
* exception since data don't match.
1003+
*/
1004+
1005+
SWSS_LOG_THROW("recorded status is %s but returned is %s on %s",
1006+
sai_serialize_status(recorded_statuses[i]).c_str(),
1007+
sai_serialize_status(statuses[i]).c_str(),
1008+
object_ids[i].c_str());
1009+
}
1010+
}
1011+
1012+
return status;
1013+
1014+
}
9671015
else
9681016
{
9691017
SWSS_LOG_THROW("api %d is not supported in bulk route", api);
@@ -981,7 +1029,8 @@ void processBulk(
9811029
return;
9821030
}
9831031

984-
if (api != (sai_common_api_t)SAI_COMMON_API_BULK_SET)
1032+
if (api != (sai_common_api_t)SAI_COMMON_API_BULK_SET &&
1033+
api != (sai_common_api_t)SAI_COMMON_API_BULK_CREATE)
9851034
{
9861035
SWSS_LOG_THROW("bulk common api %d is not supported yet, FIXME", api);
9871036
}
@@ -1154,6 +1203,9 @@ int replay(int argc, char **argv)
11541203
case 'S':
11551204
processBulk((sai_common_api_t)SAI_COMMON_API_BULK_SET, line);
11561205
continue;
1206+
case 'C':
1207+
processBulk((sai_common_api_t)SAI_COMMON_API_BULK_CREATE, line);
1208+
continue;
11571209
case 'g':
11581210
api = SAI_COMMON_API_GET;
11591211
break;

0 commit comments

Comments
 (0)