Skip to content

Commit b43af79

Browse files
authored
Allow set readonly attributes in unittest mode for easier testing (sonic-net#273)
1 parent 3b817bb commit b43af79

File tree

5 files changed

+200
-2
lines changed

5 files changed

+200
-2
lines changed

meta/sai_meta.cpp

+89-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,86 @@
1414
#include <map>
1515
#include <iterator>
1616

17+
static volatile bool unittests_enabled = false;
18+
19+
static std::set<std::string> meta_unittests_set_readonly_set;
20+
21+
void meta_unittests_enable(
22+
_In_ bool enable)
23+
{
24+
SWSS_LOG_ENTER();
25+
26+
unittests_enabled = enable;
27+
}
28+
29+
bool meta_unittests_enabled()
30+
{
31+
SWSS_LOG_ENTER();
32+
33+
return unittests_enabled;
34+
}
35+
36+
sai_status_t meta_unittests_allow_readonly_set_once(
37+
_In_ sai_object_type_t object_type,
38+
_In_ int32_t attr_id)
39+
{
40+
SWSS_LOG_ENTER();
41+
42+
if (!unittests_enabled)
43+
{
44+
SWSS_LOG_NOTICE("unittests are not enabled");
45+
return SAI_STATUS_FAILURE;
46+
}
47+
48+
auto *md = sai_metadata_get_attr_metadata(object_type, attr_id);
49+
50+
if (md == NULL)
51+
{
52+
SWSS_LOG_ERROR("failed to get metadata for object type %d and attr id %d", object_type, attr_id);
53+
return SAI_STATUS_FAILURE;
54+
}
55+
56+
if (!HAS_FLAG_READ_ONLY(md->flags))
57+
{
58+
SWSS_LOG_ERROR("attribute %s is not marked as READ_ONLY", md->attridname);
59+
return SAI_STATUS_FAILURE;
60+
}
61+
62+
meta_unittests_set_readonly_set.insert(md->attridname);
63+
64+
SWSS_LOG_INFO("enabling SET for readonly attribute: %s", md->attridname);
65+
66+
return SAI_STATUS_SUCCESS;
67+
}
68+
69+
static bool meta_unittests_get_and_erase_set_readonly_flag(
70+
_In_ const sai_attr_metadata_t& md)
71+
{
72+
SWSS_LOG_ENTER();
73+
74+
if (!unittests_enabled)
75+
{
76+
// explicityly to not produce false alarms
77+
SWSS_LOG_NOTICE("unittests are not enabled");
78+
return false;
79+
}
80+
81+
const auto &it = meta_unittests_set_readonly_set.find(md.attridname);
82+
83+
if (it == meta_unittests_set_readonly_set.end())
84+
{
85+
SWSS_LOG_ERROR("%s is not present in readonly set", md.attridname);
86+
return false;
87+
}
88+
89+
SWSS_LOG_INFO("%s is present in readonly set, erasing", md.attridname);
90+
91+
meta_unittests_set_readonly_set.erase(it);
92+
93+
return true;
94+
}
95+
96+
1797
// TODO move to metadata utils
1898
bool is_ipv6_mask_valid(
1999
_In_ const uint8_t* mask)
@@ -1647,9 +1727,16 @@ sai_status_t meta_generic_validation_set(
16471727

16481728
if (HAS_FLAG_READ_ONLY(md.flags))
16491729
{
1650-
META_LOG_ERROR(md, "attr is read only and cannot be modified");
1730+
if (meta_unittests_get_and_erase_set_readonly_flag(md))
1731+
{
1732+
META_LOG_NOTICE(md, "readonly attribute is allowd to be set (unittests enabled)");
1733+
}
1734+
else
1735+
{
1736+
META_LOG_ERROR(md, "attr is read only and cannot be modified");
16511737

1652-
return SAI_STATUS_INVALID_PARAMETER;
1738+
return SAI_STATUS_INVALID_PARAMETER;
1739+
}
16531740
}
16541741

16551742
if (HAS_FLAG_CREATE_ONLY(md.flags))

meta/sai_meta.h

+58
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,62 @@ extern void meta_sai_on_fdb_event(
158158
_In_ uint32_t count,
159159
_In_ sai_fdb_event_notification_data_t *data);
160160

161+
// UNIT TESTS HELPERS
162+
163+
/**
164+
* @brief Enable unittest globally.
165+
*
166+
* @param[in] enable If set to true unittests are enabled.
167+
*/
168+
void meta_unittests_enable(
169+
_In_ bool enable);
170+
171+
/**
172+
* @brief Indicates whethre unittests are enabled;
173+
*/
174+
bool meta_unittests_enabled();
175+
176+
/**
177+
* @bried Allow to perform SET operation on READ_ONLY attribue only once.
178+
*
179+
* This function relaxes metadata checking on SET operation, it allows to
180+
* perform SET api on READ_ONLY attribute only once on specific object type and
181+
* specific attribue.
182+
*
183+
* Once means that SET operation is only relaxed for the very next SET call on
184+
* that specific object type and attrirbute id.
185+
*
186+
* Function is explicitly named ONCE, since it will force test developer to not
187+
* forget that SET check is relaxed, and not forget for future unittests.
188+
*
189+
* Function is provided for more flexible testing using virtual switch. Since
190+
* some of the read only attributes maybe very complex to simulate (for example
191+
* resources used by actual asic when adding next hop or next hop group), then
192+
* it's easier to write such unittest:
193+
*
194+
* TestCase:
195+
* 1. meta_unittests_allow_readonly_set_once(x,y);
196+
* 2. object_x_api->set_attribyte(object_id, attr, foo); // attr.id == y
197+
* 3. object_x_api->get_attribute(object_id, 1, attr); // attr.id == y
198+
* 4. check if get result is equal to set result.
199+
*
200+
* On real ASIC, even after allowing SET on read only attribute, actual SET
201+
* should fail.
202+
*
203+
* It can be dangerous to set any readonly attribute to different values since
204+
* internal metadata logic maybe using that value and in some cases metadata
205+
* database may get out of sync and cause unexpected results in api calls up to
206+
* application carash.
207+
*
208+
* This function is not thread safe.
209+
*
210+
* @param[in] object_type Object type on which SET will be possible.
211+
* @param[in] attr_id Attribute ID on which SET will be possible.
212+
*
213+
* @return #SAI_STATUS_SUCCESS on success Failure status code on error
214+
*/
215+
sai_status_t meta_unittests_allow_readonly_set_once(
216+
_In_ sai_object_type_t object_type,
217+
_In_ int32_t attr_id);
218+
161219
#endif // __SAI_META_H__

vslib/src/sai_vs_switch_BCM56850.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,13 @@ sai_status_t refresh_read_only_BCM56850(
11431143
return refresh_vlan_member_list(meta, object_id, switch_id);
11441144
}
11451145

1146+
if (meta_unittests_enabled())
1147+
{
1148+
SWSS_LOG_NOTICE("unittests enabled, SET could be performed on %s, not recalculating", meta->attridname);
1149+
1150+
return SAI_STATUS_SUCCESS;
1151+
}
1152+
11461153
SWSS_LOG_WARN("need to recalculate RO: %s", meta->attridname);
11471154

11481155
return SAI_STATUS_NOT_IMPLEMENTED;

vslib/src/sai_vs_switch_MLNX2700.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,13 @@ sai_status_t refresh_read_only_MLNX2700(
11221122
return refresh_vlan_member_list(meta, object_id, switch_id);
11231123
}
11241124

1125+
if (meta_unittests_enabled())
1126+
{
1127+
SWSS_LOG_NOTICE("unittests enabled, SET could be performed on %s, not recalculating", meta->attridname);
1128+
1129+
return SAI_STATUS_SUCCESS;
1130+
}
1131+
11251132
SWSS_LOG_WARN("need to recalculate RO: %s", meta->attridname);
11261133

11271134
return SAI_STATUS_NOT_IMPLEMENTED;

vslib/src/tests.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,43 @@ void test_ports()
137137
ASSERT_TRUE(attr.value.objlist.count == expected_ports);
138138
}
139139

140+
void test_set_readonly_attribute()
141+
{
142+
SWSS_LOG_ENTER();
143+
144+
sai_attribute_t attr;
145+
146+
sai_object_id_t switch_id;
147+
148+
attr.id = SAI_SWITCH_ATTR_INIT_SWITCH;
149+
attr.value.booldata = true;
150+
151+
SUCCESS(sai_metadata_sai_switch_api->create_switch(&switch_id, 1, &attr));
152+
153+
attr.id = SAI_SWITCH_ATTR_PORT_MAX_MTU;
154+
attr.value.u32 = 42;
155+
156+
ASSERT_TRUE(sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr) != SAI_STATUS_SUCCESS);
157+
158+
meta_unittests_enable(true);
159+
160+
// allow set on readonly attribute
161+
SUCCESS(meta_unittests_allow_readonly_set_once(SAI_OBJECT_TYPE_SWITCH, SAI_SWITCH_ATTR_PORT_MAX_MTU));
162+
163+
// set on readonly attribute should pass
164+
SUCCESS(sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr));
165+
166+
// just scramble value to make sure that GET will succeed
167+
attr.value.u32 = 1;
168+
169+
SUCCESS(sai_metadata_sai_switch_api->get_switch_attribute(switch_id, 1, &attr));
170+
171+
ASSERT_TRUE(attr.value.u32 == 42);
172+
173+
// second SET should fail
174+
ASSERT_TRUE(sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr) != SAI_STATUS_SUCCESS);
175+
}
176+
140177
int main()
141178
{
142179
swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG);
@@ -153,5 +190,7 @@ int main()
153190

154191
test_ports();
155192

193+
test_set_readonly_attribute();
194+
156195
return 0;
157196
}

0 commit comments

Comments
 (0)