Skip to content

Commit 1dab495

Browse files
authored
Avoid aborting orchagent when setting TUNNEL attributes (sonic-net#2591)
- What I did Avoid aborting orchagent when setting TUNNEL attributes - Why I did it Do not abort orchagent if vendor SAI returns SAI_STATUS_ATTR_NOT_SUPPORTED_0 Currently, the logic is hit while setting TUNNEL|MuxTunnel0 table for DSCP remapping. For some vendors SAI returns “SAI_STATUS_ATTR_NOT_SUPPORTED_0” in such case. The fix is to avoid aborting orchagent if vendor SAI returns that return value and just to log error message. Skip setting create-only attributes, including “ecn_mode” and “encap_ecn_mode” This is because both SAI attributes are “create-only” according to the community SAI header definition, which means setting on either attribute is illegal. It’s a common limitation for all vendors. The fix is to skip such attributes when they are updated. Also, the logic in setTunnelAttribute to handle both attributes is removed since it’s dead code. - How I verified it Added new unit test to cover the new errors returned and avoiding the abort flow Signed-off-by: Stephen Sun <[email protected]>
1 parent 4395cea commit 1dab495

File tree

3 files changed

+147
-27
lines changed

3 files changed

+147
-27
lines changed

orchagent/orch.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,18 @@ task_process_status Orch::handleSaiSetStatus(sai_api_t api, sai_status_t status,
959959
sai_serialize_api(api).c_str(), sai_serialize_status(status).c_str());
960960
abort();
961961
}
962+
case SAI_API_TUNNEL:
963+
switch (status)
964+
{
965+
case SAI_STATUS_ATTR_NOT_SUPPORTED_0:
966+
SWSS_LOG_ERROR("Encountered SAI_STATUS_ATTR_NOT_SUPPORTED_0 in set operation, task failed, SAI API: %s, status: %s",
967+
sai_serialize_api(api).c_str(), sai_serialize_status(status).c_str());
968+
return task_failed;
969+
default:
970+
SWSS_LOG_ERROR("Encountered failure in set operation, exiting orchagent, SAI API: %s, status: %s",
971+
sai_serialize_api(api).c_str(), sai_serialize_status(status).c_str());
972+
abort();
973+
}
962974
default:
963975
SWSS_LOG_ERROR("Encountered failure in set operation, exiting orchagent, SAI API: %s, status: %s",
964976
sai_serialize_api(api).c_str(), sai_serialize_status(status).c_str());

orchagent/tunneldecaporch.cpp

+6-26
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ void TunnelDecapOrch::doTask(Consumer& consumer)
144144
}
145145
if (exists)
146146
{
147-
setTunnelAttribute(fvField(i), ecn_mode, tunnel_id);
147+
SWSS_LOG_NOTICE("Skip setting ecn_mode since the SAI attribute SAI_TUNNEL_ATTR_DECAP_ECN_MODE is create only");
148+
valid = false;
149+
break;
148150
}
149151
}
150152
else if (fvField(i) == "encap_ecn_mode")
@@ -158,7 +160,9 @@ void TunnelDecapOrch::doTask(Consumer& consumer)
158160
}
159161
if (exists)
160162
{
161-
setTunnelAttribute(fvField(i), encap_ecn_mode, tunnel_id);
163+
SWSS_LOG_NOTICE("Skip setting encap_ecn_mode since the SAI attribute SAI_TUNNEL_ATTR_ENCAP_ECN_MODE is create only");
164+
valid = false;
165+
break;
162166
}
163167
}
164168
else if (fvField(i) == "ttl_mode")
@@ -582,30 +586,6 @@ bool TunnelDecapOrch::setTunnelAttribute(string field, string value, sai_object_
582586

583587
sai_attribute_t attr;
584588

585-
if (field == "ecn_mode")
586-
{
587-
// decap ecn mode (copy from outer/standard)
588-
attr.id = SAI_TUNNEL_ATTR_DECAP_ECN_MODE;
589-
if (value == "copy_from_outer")
590-
{
591-
attr.value.s32 = SAI_TUNNEL_DECAP_ECN_MODE_COPY_FROM_OUTER;
592-
}
593-
else if (value == "standard")
594-
{
595-
attr.value.s32 = SAI_TUNNEL_DECAP_ECN_MODE_STANDARD;
596-
}
597-
}
598-
599-
if (field == "encap_ecn_mode")
600-
{
601-
// encap ecn mode (only standard is supported)
602-
attr.id = SAI_TUNNEL_ATTR_ENCAP_ECN_MODE;
603-
if (value == "standard")
604-
{
605-
attr.value.s32 = SAI_TUNNEL_ENCAP_ECN_MODE_STANDARD;
606-
}
607-
}
608-
609589
if (field == "ttl_mode")
610590
{
611591
// ttl mode (uniform/pipe)

tests/mock_tests/qosorch_ut.cpp

+129-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ namespace qosorch_test
2525
int sai_remove_scheduler_count;
2626
int sai_set_wred_attribute_count;
2727
sai_object_id_t switch_dscp_to_tc_map_id;
28+
TunnelDecapOrch *tunnel_decap_orch;
2829

2930
sai_remove_scheduler_fn old_remove_scheduler;
3031
sai_scheduler_api_t ut_sai_scheduler_api, *pold_sai_scheduler_api;
@@ -36,6 +37,7 @@ namespace qosorch_test
3637
sai_qos_map_api_t ut_sai_qos_map_api, *pold_sai_qos_map_api;
3738
sai_set_switch_attribute_fn old_set_switch_attribute_fn;
3839
sai_switch_api_t ut_sai_switch_api, *pold_sai_switch_api;
40+
sai_tunnel_api_t ut_sai_tunnel_api, *pold_sai_tunnel_api;
3941

4042
typedef struct
4143
{
@@ -212,6 +214,40 @@ namespace qosorch_test
212214
return rc;
213215
}
214216

217+
sai_status_t _ut_stub_sai_create_tunnel(
218+
_Out_ sai_object_id_t *tunnel_id,
219+
_In_ sai_object_id_t switch_id,
220+
_In_ uint32_t attr_count,
221+
_In_ const sai_attribute_t *attr_list)
222+
{
223+
*tunnel_id = (sai_object_id_t)(0x1);
224+
return SAI_STATUS_SUCCESS;
225+
}
226+
227+
sai_status_t _ut_stub_sai_create_tunnel_term_table_entry(
228+
_Out_ sai_object_id_t *tunnel_term_table_entry_id,
229+
_In_ sai_object_id_t switch_id,
230+
_In_ uint32_t attr_count,
231+
_In_ const sai_attribute_t *attr_list)
232+
{
233+
*tunnel_term_table_entry_id = (sai_object_id_t)(0x1);
234+
return SAI_STATUS_SUCCESS;
235+
}
236+
237+
void checkTunnelAttribute(sai_attr_id_t attr)
238+
{
239+
ASSERT_TRUE(attr != SAI_TUNNEL_ATTR_ENCAP_ECN_MODE);
240+
ASSERT_TRUE(attr != SAI_TUNNEL_ATTR_DECAP_ECN_MODE);
241+
}
242+
243+
sai_status_t _ut_stub_sai_set_tunnel_attribute(
244+
_In_ sai_object_id_t tunnel_id,
245+
_In_ const sai_attribute_t *attr)
246+
{
247+
checkTunnelAttribute(attr->id);
248+
return SAI_STATUS_ATTR_NOT_SUPPORTED_0;
249+
}
250+
215251
struct QosOrchTest : public ::testing::Test
216252
{
217253
QosOrchTest()
@@ -292,6 +328,14 @@ namespace qosorch_test
292328
sai_switch_api = &ut_sai_switch_api;
293329
ut_sai_switch_api.set_switch_attribute = _ut_stub_sai_set_switch_attribute;
294330

331+
// Mock tunnel API
332+
pold_sai_tunnel_api = sai_tunnel_api;
333+
ut_sai_tunnel_api = *pold_sai_tunnel_api;
334+
sai_tunnel_api = &ut_sai_tunnel_api;
335+
ut_sai_tunnel_api.set_tunnel_attribute = _ut_stub_sai_set_tunnel_attribute;
336+
ut_sai_tunnel_api.create_tunnel = _ut_stub_sai_create_tunnel;
337+
ut_sai_tunnel_api.create_tunnel_term_table_entry = _ut_stub_sai_create_tunnel_term_table_entry;
338+
295339
// Init switch and create dependencies
296340
m_app_db = make_shared<swss::DBConnector>("APPL_DB", 0);
297341
m_config_db = make_shared<swss::DBConnector>("CONFIG_DB", 0);
@@ -381,6 +425,9 @@ namespace qosorch_test
381425
ASSERT_EQ(gNeighOrch, nullptr);
382426
gNeighOrch = new NeighOrch(m_app_db.get(), APP_NEIGH_TABLE_NAME, gIntfsOrch, gFdbOrch, gPortsOrch, m_chassis_app_db.get());
383427

428+
ASSERT_EQ(tunnel_decap_orch, nullptr);
429+
tunnel_decap_orch = new TunnelDecapOrch(m_app_db.get(), APP_TUNNEL_DECAP_TABLE_NAME);
430+
384431
vector<string> qos_tables = {
385432
CFG_TC_TO_QUEUE_MAP_TABLE_NAME,
386433
CFG_SCHEDULER_TABLE_NAME,
@@ -394,7 +441,8 @@ namespace qosorch_test
394441
CFG_PFC_PRIORITY_TO_PRIORITY_GROUP_MAP_TABLE_NAME,
395442
CFG_PFC_PRIORITY_TO_QUEUE_MAP_TABLE_NAME,
396443
CFG_DSCP_TO_FC_MAP_TABLE_NAME,
397-
CFG_EXP_TO_FC_MAP_TABLE_NAME
444+
CFG_EXP_TO_FC_MAP_TABLE_NAME,
445+
CFG_TC_TO_DSCP_MAP_TABLE_NAME
398446
};
399447
gQosOrch = new QosOrch(m_config_db.get(), qos_tables);
400448

@@ -557,10 +605,14 @@ namespace qosorch_test
557605
delete gQosOrch;
558606
gQosOrch = nullptr;
559607

608+
delete tunnel_decap_orch;
609+
tunnel_decap_orch = nullptr;
610+
560611
sai_qos_map_api = pold_sai_qos_map_api;
561612
sai_scheduler_api = pold_sai_scheduler_api;
562613
sai_wred_api = pold_sai_wred_api;
563614
sai_switch_api = pold_sai_switch_api;
615+
sai_tunnel_api = pold_sai_tunnel_api;
564616
ut_helper::uninitSaiApi();
565617
}
566618
};
@@ -1458,4 +1510,80 @@ namespace qosorch_test
14581510
// Drain DSCP_TO_TC_MAP and PORT_QOS_MAP table
14591511
static_cast<Orch *>(gQosOrch)->doTask();
14601512
}
1513+
1514+
/*
1515+
* Set tunnel QoS attribute test - OA should skip settings
1516+
*/
1517+
TEST_F(QosOrchTest, QosOrchTestSetTunnelQoSAttribute)
1518+
{
1519+
// Create a new dscp to tc map
1520+
Table tcToDscpMapTable = Table(m_config_db.get(), CFG_TC_TO_DSCP_MAP_TABLE_NAME);
1521+
tcToDscpMapTable.set("AZURE",
1522+
{
1523+
{"0", "0"},
1524+
{"1", "1"}
1525+
});
1526+
gQosOrch->addExistingData(&tcToDscpMapTable);
1527+
static_cast<Orch *>(gQosOrch)->doTask();
1528+
1529+
std::deque<KeyOpFieldsValuesTuple> entries;
1530+
entries.push_back({"MuxTunnel0", "SET",
1531+
{
1532+
{"decap_dscp_to_tc_map", "AZURE"},
1533+
{"decap_tc_to_pg_map", "AZURE"},
1534+
{"dscp_mode", "pipe"},
1535+
{"dst_ip", "10.1.0.32"},
1536+
{"encap_tc_to_dscp_map", "AZURE"},
1537+
{"encap_tc_to_queue_map", "AZURE"},
1538+
{"src_ip", "10.1.0.33"},
1539+
{"ttl_mode", "pipe"},
1540+
{"tunnel_type", "IPINIP"}
1541+
}});
1542+
entries.push_back({"MuxTunnel1", "SET",
1543+
{
1544+
{"decap_dscp_to_tc_map", "AZURE"},
1545+
{"dscp_mode", "pipe"},
1546+
{"dst_ip", "10.1.0.32"},
1547+
{"encap_tc_to_dscp_map", "AZURE"},
1548+
{"encap_tc_to_queue_map", "AZURE"},
1549+
{"src_ip", "10.1.0.33"},
1550+
{"ttl_mode", "pipe"},
1551+
{"tunnel_type", "IPINIP"}
1552+
}});
1553+
auto consumer = dynamic_cast<Consumer *>(tunnel_decap_orch->getExecutor(APP_TUNNEL_DECAP_TABLE_NAME));
1554+
consumer->addToSync(entries);
1555+
// Drain TUNNEL_DECAP_TABLE table
1556+
static_cast<Orch *>(tunnel_decap_orch)->doTask();
1557+
entries.clear();
1558+
1559+
// Set an attribute that is not supported by vendor
1560+
entries.push_back({"MuxTunnel1", "SET",
1561+
{
1562+
{"decap_tc_to_pg_map", "AZURE"}
1563+
}});
1564+
consumer->addToSync(entries);
1565+
// Drain TUNNEL_DECAP_TABLE table
1566+
static_cast<Orch *>(tunnel_decap_orch)->doTask();
1567+
entries.clear();
1568+
1569+
// Set attributes for the 2nd time
1570+
entries.push_back({"MuxTunnel0", "SET",
1571+
{
1572+
{"encap_ecn_mode", "standard"}
1573+
}});
1574+
consumer->addToSync(entries);
1575+
// Drain TUNNEL_DECAP_TABLE table
1576+
static_cast<Orch *>(tunnel_decap_orch)->doTask();
1577+
entries.clear();
1578+
1579+
// Set attributes for the 2nd time
1580+
entries.push_back({"MuxTunnel1", "SET",
1581+
{
1582+
{"ecn_mode", "copy_from_outer"}
1583+
}});
1584+
consumer->addToSync(entries);
1585+
// Drain TUNNEL_DECAP_TABLE table
1586+
static_cast<Orch *>(tunnel_decap_orch)->doTask();
1587+
entries.clear();
1588+
}
14611589
}

0 commit comments

Comments
 (0)