Skip to content

Commit d644d2e

Browse files
authored
[bulker] Add support for bulk set object attributes (sonic-net#3703)
Adds bulker API to allow bulk set attribute operations in orchagent. Adds unit test for bulker to test adding nexthops, setting nexthop attributes, and removing nexthops What I did Added support for bulk setting object attributes in orchagent Why I did it bulk nexthop attribute setting is supported in SAI and will help with efforts in imporoving dualtor switchover times.
1 parent eae91a2 commit d644d2e

File tree

4 files changed

+225
-29
lines changed

4 files changed

+225
-29
lines changed

orchagent/bulker.h

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,7 @@ struct SaiBulkerTraits<sai_next_hop_group_api_t>
368368
using set_entry_attribute_fn = sai_set_next_hop_group_member_attribute_fn;
369369
using bulk_create_entry_fn = sai_bulk_object_create_fn;
370370
using bulk_remove_entry_fn = sai_bulk_object_remove_fn;
371-
// TODO: wait until available in SAI
372-
//using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
371+
using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
373372
};
374373

375374
template<>
@@ -382,8 +381,7 @@ struct SaiBulkerTraits<sai_next_hop_api_t>
382381
using set_entry_attribute_fn = sai_set_next_hop_attribute_fn;
383382
using bulk_create_entry_fn = sai_bulk_object_create_fn;
384383
using bulk_remove_entry_fn = sai_bulk_object_remove_fn;
385-
// TODO: wait until available in SAI
386-
//using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
384+
using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
387385
};
388386

389387
template<>
@@ -422,6 +420,7 @@ struct SaiBulkerTraits<sai_dash_meter_api_t>
422420
using set_entry_attribute_fn = sai_set_meter_rule_attribute_fn;
423421
using bulk_create_entry_fn = sai_bulk_object_create_fn;
424422
using bulk_remove_entry_fn = sai_bulk_object_remove_fn;
423+
using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
425424
};
426425

427426
template<>
@@ -434,6 +433,7 @@ struct SaiBulkerTraits<sai_dash_vnet_api_t>
434433
using set_entry_attribute_fn = sai_set_vnet_attribute_fn;
435434
using bulk_create_entry_fn = sai_bulk_object_create_fn;
436435
using bulk_remove_entry_fn = sai_bulk_object_remove_fn;
436+
using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
437437
};
438438

439439
template<>
@@ -495,6 +495,7 @@ struct SaiBulkerTraits<sai_dash_tunnel_api_t>
495495
using api_t = sai_dash_tunnel_api_t;
496496
using bulk_create_entry_fn = sai_bulk_object_create_fn;
497497
using bulk_remove_entry_fn = sai_bulk_object_remove_fn;
498+
using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn;
498499
};
499500

500501
template<>
@@ -1071,8 +1072,6 @@ class ObjectBulker
10711072
return *object_status;
10721073
}
10731074

1074-
// TODO: wait until available in SAI
1075-
/*
10761075
sai_status_t set_entry_attribute(
10771076
_In_ sai_object_id_t object_id,
10781077
_In_ const sai_attribute_t *attr)
@@ -1086,14 +1085,15 @@ class ObjectBulker
10861085
else
10871086
{
10881087
// Create a new key if not exists in the map
1089-
setting_entries.emplace(std::piecewise_construct,
1088+
auto& attrs = setting_entries.emplace(std::piecewise_construct,
10901089
std::forward_as_tuple(object_id),
1091-
std::forward_as_tuple(1, *attr));
1090+
std::forward_as_tuple()).first->second;
1091+
1092+
attrs.emplace_back(*attr);
10921093
}
10931094

10941095
return SAI_STATUS_SUCCESS;
10951096
}
1096-
*/
10971097

10981098
void flush()
10991099
{
@@ -1149,9 +1149,6 @@ class ObjectBulker
11491149
creating_entries.clear();
11501150
}
11511151

1152-
// Setting
1153-
// TODO: wait until available in SAI
1154-
/*
11551152
if (!setting_entries.empty())
11561153
{
11571154
std::vector<sai_object_id_t> rs;
@@ -1176,7 +1173,6 @@ class ObjectBulker
11761173

11771174
setting_entries.clear();
11781175
}
1179-
*/
11801176
}
11811177

11821178
void clear()
@@ -1228,11 +1224,8 @@ class ObjectBulker
12281224
>> creating_entries;
12291225

12301226
std::unordered_map< // A map of
1231-
sai_object_id_t, // object_id -> (OUT object_status, attributes)
1232-
std::pair<
1233-
sai_status_t *,
1234-
std::vector<sai_attribute_t>
1235-
>
1227+
sai_object_id_t, // object_id -> attrs
1228+
std::vector<sai_attribute_t>
12361229
> setting_entries;
12371230

12381231
// A map of
@@ -1241,8 +1234,7 @@ class ObjectBulker
12411234

12421235
sai_bulk_object_create_fn create_entries;
12431236
sai_bulk_object_remove_fn remove_entries;
1244-
// TODO: wait until available in SAI
1245-
//typename Ts::bulk_set_entry_attribute_fn set_entries_attribute;
1237+
sai_bulk_object_set_attribute_fn set_entries_attribute;
12461238

12471239
std::unordered_map<sai_object_id_t, sai_status_t> create_statuses;
12481240

@@ -1316,8 +1308,6 @@ class ObjectBulker
13161308
return status;
13171309
}
13181310

1319-
// TODO: wait until available in SAI
1320-
/*
13211311
sai_status_t flush_setting_entries(
13221312
_Inout_ std::vector<sai_object_id_t> &rs,
13231313
_Inout_ std::vector<sai_attribute_t> &ts)
@@ -1328,8 +1318,8 @@ class ObjectBulker
13281318
}
13291319
size_t count = rs.size();
13301320
std::vector<sai_status_t> statuses(count);
1331-
sai_status_t status = (*set_entries_attribute)((uint32_t)count, rs.data(), ts.data()
1332-
, SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR, statuses.data());
1321+
sai_status_t status = (*set_entries_attribute)((uint32_t)count, rs.data(), ts.data(),
1322+
SAI_BULK_OP_ERROR_MODE_STOP_ON_ERROR, statuses.data());
13331323
if (status == SAI_STATUS_SUCCESS)
13341324
{
13351325
SWSS_LOG_INFO("ObjectBulker.flush setting_entries %zu\n", count);
@@ -1345,7 +1335,6 @@ class ObjectBulker
13451335

13461336
return status;
13471337
}
1348-
*/
13491338
};
13501339

13511340
template <>
@@ -1355,8 +1344,7 @@ inline ObjectBulker<sai_next_hop_group_api_t>::ObjectBulker(SaiBulkerTraits<sai_
13551344
{
13561345
create_entries = api->create_next_hop_group_members;
13571346
remove_entries = api->remove_next_hop_group_members;
1358-
// TODO: wait until available in SAI
1359-
//set_entries_attribute = ;
1347+
set_entries_attribute = api->set_next_hop_group_members_attribute;
13601348
}
13611349

13621350
template <>
@@ -1366,8 +1354,7 @@ inline ObjectBulker<sai_next_hop_api_t>::ObjectBulker(SaiBulkerTraits<sai_next_h
13661354
{
13671355
create_entries = api->create_next_hops;
13681356
remove_entries = api->remove_next_hops;
1369-
// TODO: wait until available in SAI
1370-
//set_entries_attribute = ;
1357+
set_entries_attribute = api->set_next_hops_attribute;
13711358
}
13721359

13731360
template <>
@@ -1377,6 +1364,7 @@ inline ObjectBulker<sai_dash_vnet_api_t>::ObjectBulker(SaiBulkerTraits<sai_dash_
13771364
{
13781365
create_entries = api->create_vnets;
13791366
remove_entries = api->remove_vnets;
1367+
set_entries_attribute = nullptr;
13801368
}
13811369

13821370
template <>
@@ -1386,6 +1374,7 @@ inline ObjectBulker<sai_dash_meter_api_t>::ObjectBulker(SaiBulkerTraits<sai_dash
13861374
{
13871375
create_entries = api->create_meter_rules;
13881376
remove_entries = api->remove_meter_rules;
1377+
set_entries_attribute = nullptr;
13891378
}
13901379

13911380
template <>
@@ -1398,14 +1387,17 @@ inline ObjectBulker<sai_dash_tunnel_api_t>::ObjectBulker(SaiBulkerTraits<sai_das
13981387
case SAI_OBJECT_TYPE_DASH_TUNNEL:
13991388
create_entries = api->create_dash_tunnels;
14001389
remove_entries = api->remove_dash_tunnels;
1390+
set_entries_attribute = nullptr;
14011391
break;
14021392
case SAI_OBJECT_TYPE_DASH_TUNNEL_MEMBER:
14031393
create_entries = api->create_dash_tunnel_members;
14041394
remove_entries = api->remove_dash_tunnel_members;
1395+
set_entries_attribute = nullptr;
14051396
break;
14061397
case SAI_OBJECT_TYPE_DASH_TUNNEL_NEXT_HOP:
14071398
create_entries = api->create_dash_tunnel_next_hops;
14081399
remove_entries = api->remove_dash_tunnel_next_hops;
1400+
set_entries_attribute = nullptr;
14091401
break;
14101402
default:
14111403
std::string type_str = sai_serialize_object_type((sai_object_type_t) object_type);

orchagent/p4orch/tests/mock_sai_next_hop.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ class MockSaiNextHop
2929

3030
MOCK_METHOD4(remove_next_hops, sai_status_t(_In_ uint32_t object_count, _In_ const sai_object_id_t *object_id, _In_ sai_bulk_op_error_mode_t mode,
3131
_Out_ sai_status_t *object_statuses));
32+
33+
MOCK_METHOD5(set_next_hops_attribute, sai_status_t(_In_ uint32_t object_count, _In_ const sai_object_id_t *object_id, _In_ const sai_attribute_t *attr_list,
34+
_In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses));
3235
};
3336

3437
// Note that before mock functions below are used, mock_sai_next_hop must be
@@ -51,3 +54,6 @@ sai_status_t mock_create_next_hops(_In_ sai_object_id_t switch_id, _In_ uint32_t
5154

5255
sai_status_t mock_remove_next_hops(_In_ uint32_t object_count, _In_ const sai_object_id_t *object_id, _In_ sai_bulk_op_error_mode_t mode,
5356
_Out_ sai_status_t *object_statuses);
57+
58+
sai_status_t mock_set_next_hops_attribute(_In_ uint32_t object_count, _In_ const sai_object_id_t *object_id, _In_ const sai_attribute_t *attr_list,
59+
_In_ sai_bulk_op_error_mode_t mode, _Out_ sai_status_t *object_statuses);

tests/mock_tests/bulker_ut.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
#include "ut_helper.h"
22
#include "bulker.h"
3+
#include "mock_sai_api.h"
34

45
extern sai_route_api_t *sai_route_api;
56
extern sai_neighbor_api_t *sai_neighbor_api;
7+
extern sai_next_hop_api_t *sai_next_hop_api;
8+
9+
EXTERN_MOCK_FNS
610

711
namespace bulker_test
812
{
913
using namespace std;
14+
using ::testing::SetArrayArgument;
15+
using ::testing::Return;
16+
using ::testing::DoAll;
17+
18+
DEFINE_SAI_GENERIC_API_OBJECT_BULK_MOCK_WITH_SET(next_hop, next_hop);
19+
20+
sai_bulk_object_create_fn old_object_create;
21+
sai_bulk_object_remove_fn old_object_remove;
22+
sai_bulk_object_set_attribute_fn old_object_set_attribute;
1023

1124
struct BulkerTest : public ::testing::Test
1225
{
@@ -21,15 +34,36 @@ namespace bulker_test
2134

2235
ASSERT_EQ(sai_neighbor_api, nullptr);
2336
sai_neighbor_api = new sai_neighbor_api_t();
37+
38+
ASSERT_EQ(sai_next_hop_api, nullptr);
39+
sai_next_hop_api = new sai_next_hop_api_t();
40+
41+
INIT_SAI_API_MOCK(next_hop);
42+
MockSaiApis();
43+
old_object_create = sai_next_hop_api->create_next_hops;
44+
old_object_remove = sai_next_hop_api->remove_next_hops;
45+
old_object_set_attribute = sai_next_hop_api->set_next_hops_attribute;
46+
sai_next_hop_api->create_next_hops = mock_create_next_hops;
47+
sai_next_hop_api->remove_next_hops = mock_remove_next_hops;
48+
sai_next_hop_api->set_next_hops_attribute = mock_set_next_hops_attribute;
2449
}
2550

2651
void TearDown() override
2752
{
53+
RestoreSaiApis();
54+
DEINIT_SAI_API_MOCK(next_hop);
55+
sai_next_hop_api->create_next_hops = old_object_create;
56+
sai_next_hop_api->remove_next_hops = old_object_remove;
57+
sai_next_hop_api->set_next_hops_attribute = old_object_set_attribute;
58+
2859
delete sai_route_api;
2960
sai_route_api = nullptr;
3061

3162
delete sai_neighbor_api;
3263
sai_neighbor_api = nullptr;
64+
65+
delete sai_next_hop_api;
66+
sai_next_hop_api = nullptr;
3367
}
3468
};
3569

@@ -174,6 +208,87 @@ namespace bulker_test
174208
ASSERT_TRUE(gNeighBulker.bulk_entry_pending_removal(neighbor_entry_remove));
175209
}
176210

211+
TEST_F(BulkerTest, ObjectBulkSet)
212+
{
213+
// Create bulker
214+
ObjectBulker<sai_next_hop_api_t> gNextHopBulker(sai_next_hop_api, 0x0, 1000);
215+
vector<sai_attribute_t> next_hop_attrs;
216+
vector<sai_object_id_t> next_hop_ids = {0x101, 0x102};
217+
vector<sai_status_t> statuses;
218+
sai_attribute_t next_hop_attr;
219+
sai_object_id_t next_hop_id_0;
220+
sai_object_id_t next_hop_id_1;
221+
std::vector<sai_status_t> exp_status{SAI_STATUS_SUCCESS, SAI_STATUS_SUCCESS};
222+
223+
// Create 2 next hops
224+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE;
225+
next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP;
226+
next_hop_attrs.push_back(next_hop_attr);
227+
228+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP;
229+
next_hop_attr.value.ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
230+
next_hop_attr.value.ipaddr.addr.ip4 = 0x10000001;
231+
next_hop_attrs.push_back(next_hop_attr);
232+
233+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID;
234+
next_hop_attr.value.oid = 0x0;
235+
next_hop_attrs.push_back(next_hop_attr);
236+
237+
gNextHopBulker.create_entry(&next_hop_id_0, (uint32_t)next_hop_attrs.size(), next_hop_attrs.data());
238+
next_hop_attrs.clear();
239+
240+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE;
241+
next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP;
242+
next_hop_attrs.push_back(next_hop_attr);
243+
244+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP;
245+
next_hop_attr.value.ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
246+
next_hop_attr.value.ipaddr.addr.ip4 = 0x10000002;
247+
next_hop_attrs.push_back(next_hop_attr);
248+
249+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID;
250+
next_hop_attr.value.oid = 0x0;
251+
next_hop_attrs.push_back(next_hop_attr);
252+
253+
gNextHopBulker.create_entry(&next_hop_id_1, (uint32_t)next_hop_attrs.size(), next_hop_attrs.data());
254+
next_hop_attrs.clear();
255+
256+
EXPECT_CALL(*mock_sai_next_hop_api, create_next_hops)
257+
.WillOnce(DoAll(
258+
SetArrayArgument<5>(next_hop_ids.begin(), next_hop_ids.end()),
259+
SetArrayArgument<6>(exp_status.begin(), exp_status.end()),
260+
Return(SAI_STATUS_SUCCESS)));
261+
gNextHopBulker.flush();
262+
263+
// Update the nexthops
264+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP;
265+
next_hop_attr.value.ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
266+
next_hop_attr.value.ipaddr.addr.ip4 = 0x10000003;
267+
268+
gNextHopBulker.set_entry_attribute(next_hop_id_0, &next_hop_attr);
269+
270+
next_hop_attr.id = SAI_NEXT_HOP_ATTR_IP;
271+
next_hop_attr.value.ipaddr.addr_family = SAI_IP_ADDR_FAMILY_IPV4;
272+
next_hop_attr.value.ipaddr.addr.ip4 = 0x10000004;
273+
next_hop_attrs.push_back(next_hop_attr);
274+
275+
gNextHopBulker.set_entry_attribute(next_hop_id_1, &next_hop_attr);
276+
277+
EXPECT_CALL(*mock_sai_next_hop_api, set_next_hops_attribute)
278+
.WillOnce(DoAll(SetArrayArgument<4>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS)));
279+
gNextHopBulker.flush();
280+
281+
// Delete the nexthops
282+
statuses.emplace_back();
283+
gNextHopBulker.remove_entry(&statuses.back(), next_hop_id_0);
284+
statuses.emplace_back();
285+
gNextHopBulker.remove_entry(&statuses.back(), next_hop_id_1);
286+
287+
EXPECT_CALL(*mock_sai_next_hop_api, remove_next_hops)
288+
.WillOnce(DoAll(SetArrayArgument<3>(exp_status.begin(), exp_status.end()), Return(SAI_STATUS_SUCCESS)));
289+
gNextHopBulker.flush();
290+
}
291+
177292
TEST_F(BulkerTest, BulkerPendingRemovalOrSet_OnlyRemoval)
178293
{
179294
// Create bulker

0 commit comments

Comments
 (0)