diff --git a/lib/inc/ServerSai.h b/lib/inc/ServerSai.h index 77ab66348ca7..fc8500a2230a 100644 --- a/lib/inc/ServerSai.h +++ b/lib/inc/ServerSai.h @@ -1,7 +1,7 @@ #pragma once #include "SaiInterface.h" - +#include "meta/SaiAttributeList.h" #include "syncd/SelectableChannel.h" #include "swss/selectableevent.h" @@ -291,6 +291,50 @@ namespace sairedis _In_ uint32_t attr_count, _In_ sai_attribute_t *attr_list); + // BULK + + sai_status_t processBulkQuadEvent( + _In_ sai_common_api_t api, + _In_ const swss::KeyOpFieldsValuesTuple &kco); + + sai_status_t processBulkOid( + _In_ sai_object_type_t objectType, + _In_ const std::vector& strObjectIds, + _In_ sai_common_api_t api, + _In_ const std::vector>& attributes, + _In_ const std::vector>& strAttributes); + + sai_status_t processBulkEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _In_ sai_common_api_t api, + _In_ const std::vector>& attributes, + _In_ const std::vector>& strAttributes); + + sai_status_t processBulkCreateEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _In_ const std::vector>& attributes, + _Out_ std::vector& statuses); + + sai_status_t processBulkRemoveEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _Out_ std::vector& statuses); + + sai_status_t processBulkSetEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _In_ const std::vector>& attributes, + _Out_ std::vector& statuses); + + void sendBulkApiResponse( + _In_ sai_common_api_t api, + _In_ sai_status_t status, + _In_ uint32_t object_count, + _In_ const sai_object_id_t* object_ids, + _In_ const sai_status_t* statuses); + private: bool m_apiInitialized; diff --git a/lib/src/ClientSai.cpp b/lib/src/ClientSai.cpp index 02ca184e513b..8e6e0782b637 100644 --- a/lib/src/ClientSai.cpp +++ b/lib/src/ClientSai.cpp @@ -746,8 +746,8 @@ sai_status_t ClientSai::waitForQueryAttributeCapabilityResponse( capability->get_implemented = (fvValue(values[2]) == "true" ? true : false); SWSS_LOG_DEBUG("Received payload: create_implemented:%s, set_implemented:%s, get_implemented:%s", - (capability->create_implemented ? "true" : "false"), - (capability->set_implemented ? "true" : "false"), + (capability->create_implemented ? "true" : "false"), + (capability->set_implemented ? "true" : "false"), (capability->get_implemented ? "true" : "false")); } @@ -1012,40 +1012,40 @@ sai_status_t ClientSai::bulkCreate( // TODO support mode - SWSS_LOG_THROW("TODO, not implemented, FIXME"); - - //for (uint32_t idx = 0; idx < object_count; idx++) - //{ - // object_id[idx] = m_virtualObjectIdManager->allocateNewObjectId(object_type, switch_id); - - // if (object_id[idx] == SAI_NULL_OBJECT_ID) - // { - // SWSS_LOG_ERROR("failed to create %s, with switch id: %s", - // sai_serialize_object_type(object_type).c_str(), - // sai_serialize_object_id(switch_id).c_str()); - - // return SAI_STATUS_INSUFFICIENT_RESOURCES; - // } - //} - - //std::vector serialized_object_ids; - - //// on create vid is put in db by syncd - //for (uint32_t idx = 0; idx < object_count; idx++) - //{ - // std::string str_object_id = sai_serialize_object_id(object_id[idx]); - // serialized_object_ids.push_back(str_object_id); - //} - - //auto status = bulkCreate( - // object_type, - // serialized_object_ids, - // attr_count, - // attr_list, - // mode, - // object_statuses); - - // TODO m_lastCreateOids + std::vector serialized_object_ids; + + // server is responsible for generate new OID but for that we need switch ID + // to be sent to server as well, so instead of sending empty oids we will + // send switch IDs + for (uint32_t idx = 0; idx < object_count; idx++) + { + serialized_object_ids.emplace_back(sai_serialize_object_id(switch_id)); + } + + auto status = bulkCreate( + object_type, + serialized_object_ids, + attr_count, + attr_list, + mode, + object_statuses); + + for (uint32_t idx = 0; idx < object_count; idx++) + { + // since user requested create, OID value was created remotely and it + // was returned in m_lastCreateOids + + if (object_statuses[idx] == SAI_STATUS_SUCCESS) + { + object_id[idx] = m_lastCreateOids.at(idx); + } + else + { + object_id[idx] = SAI_NULL_OBJECT_ID; + } + } + + return status; } sai_status_t ClientSai::bulkCreate( diff --git a/lib/src/ServerSai.cpp b/lib/src/ServerSai.cpp index 821d2f3f2868..ad03f3c3d76f 100644 --- a/lib/src/ServerSai.cpp +++ b/lib/src/ServerSai.cpp @@ -10,6 +10,7 @@ #include "swss/logger.h" #include "swss/select.h" +#include "swss/tokenize.h" using namespace sairedis; using namespace saimeta; @@ -139,10 +140,10 @@ sai_status_t ServerSai::create( REDIS_CHECK_API_INITIALIZED(); return m_sai->create( - objectType, + objectType, objectId, - switchId, - attr_count, + switchId, + attr_count, attr_list); } @@ -674,19 +675,16 @@ sai_status_t ServerSai::processSingleEvent( if (op == REDIS_ASIC_STATE_COMMAND_GET) return processQuadEvent(SAI_COMMON_API_GET, kco); + if (op == REDIS_ASIC_STATE_COMMAND_BULK_CREATE) + return processBulkQuadEvent(SAI_COMMON_API_BULK_CREATE, kco); + + if (op == REDIS_ASIC_STATE_COMMAND_BULK_REMOVE) + return processBulkQuadEvent(SAI_COMMON_API_BULK_REMOVE, kco); + + if (op == REDIS_ASIC_STATE_COMMAND_BULK_SET) + return processBulkQuadEvent(SAI_COMMON_API_BULK_SET, kco); + // TODO implement -// if (op == REDIS_ASIC_STATE_COMMAND_BULK_CREATE) -// return processBulkQuadEvent(SAI_COMMON_API_BULK_CREATE, kco); -// -// if (op == REDIS_ASIC_STATE_COMMAND_BULK_REMOVE) -// return processBulkQuadEvent(SAI_COMMON_API_BULK_REMOVE, kco); -// -// if (op == REDIS_ASIC_STATE_COMMAND_BULK_SET) -// return processBulkQuadEvent(SAI_COMMON_API_BULK_SET, kco); -// -// if (op == REDIS_ASIC_STATE_COMMAND_NOTIFY) -// return processNotifySyncd(kco); -// // if (op == REDIS_ASIC_STATE_COMMAND_GET_STATS) // return processGetStatsEvent(kco); // @@ -986,3 +984,554 @@ sai_status_t ServerSai::processOid( SWSS_LOG_THROW("common api (%s) is not implemented", sai_serialize_common_api(api).c_str()); } } + +sai_status_t ServerSai::processBulkQuadEvent( + _In_ sai_common_api_t api, + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + const std::string& key = kfvKey(kco); // objectType:count + + std::string strObjectType = key.substr(0, key.find(":")); + + sai_object_type_t objectType; + sai_deserialize_object_type(strObjectType, objectType); + + const std::vector &values = kfvFieldsValues(kco); + + std::vector> strAttributes; + + // field = objectId + // value = attrid=attrvalue|... + + std::vector objectIds; + + std::vector> attributes; + + for (const auto &fvt: values) + { + std::string strObjectId = fvField(fvt); + std::string joined = fvValue(fvt); + + // decode values + + auto v = swss::tokenize(joined, '|'); + + objectIds.push_back(strObjectId); + + std::vector entries; // attributes per object id + + for (size_t i = 0; i < v.size(); ++i) + { + const std::string item = v.at(i); + + auto start = item.find_first_of("="); + + auto field = item.substr(0, start); + auto value = item.substr(start + 1); + + entries.emplace_back(field, value); + } + + strAttributes.push_back(entries); + + // since now we converted this to proper list, we can extract attributes + + auto list = std::make_shared(objectType, entries, false); + + attributes.push_back(list); + } + + SWSS_LOG_INFO("bulk %s executing with %zu items", + strObjectType.c_str(), + objectIds.size()); + + auto info = sai_metadata_get_object_type_info(objectType); + + if (info->isobjectid) + { + return processBulkOid(objectType, objectIds, api, attributes, strAttributes); + } + else + { + return processBulkEntry(objectType, objectIds, api, attributes, strAttributes); + } +} + +sai_status_t ServerSai::processBulkOid( + _In_ sai_object_type_t objectType, + _In_ const std::vector& strObjectIds, + _In_ sai_common_api_t api, + _In_ const std::vector>& attributes, + _In_ const std::vector>& strAttributes) +{ + SWSS_LOG_ENTER(); + + auto info = sai_metadata_get_object_type_info(objectType); + + if (info->isnonobjectid) + { + SWSS_LOG_THROW("passing non object id to bulk oid object operation"); + } + + std::vector statuses(strObjectIds.size(), SAI_STATUS_FAILURE); + + sai_status_t status = SAI_STATUS_FAILURE; + + sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR; + + std::vector objectIds(strObjectIds.size()); + + for (size_t idx = 0; idx < objectIds.size(); idx++) + { + sai_deserialize_object_id(strObjectIds[idx], objectIds[idx]); + } + + size_t object_count = objectIds.size(); + + switch (api) + { + case SAI_COMMON_API_BULK_CREATE: + + { + std::vector attr_counts(object_count); + std::vector attr_lists(object_count); + + for (size_t idx = 0; idx < object_count; idx++) + { + attr_counts[idx] = attributes[idx]->get_attr_count(); + attr_lists[idx] = attributes[idx]->get_attr_list(); + } + + // in case of client/server, all passed oids are switch OID since + // client don't know what oid will be assigned to created object + sai_object_id_t switchId = objectIds.at(0); + + status = m_sai->bulkCreate( + objectType, + switchId, + (uint32_t)object_count, + attr_counts.data(), + attr_lists.data(), + mode, + objectIds.data(), + statuses.data()); + } + + break; + + case SAI_COMMON_API_BULK_REMOVE: + + status = m_sai->bulkRemove( + objectType, + (uint32_t)objectIds.size(), + objectIds.data(), + mode, + statuses.data()); + break; + + default: + status = SAI_STATUS_NOT_SUPPORTED; + SWSS_LOG_ERROR("api %s is not supported in bulk mode", sai_serialize_common_api(api).c_str()); + break; + } + + sendBulkApiResponse(api, status, (uint32_t)objectIds.size(), objectIds.data(), statuses.data()); + + return status; +} + +sai_status_t ServerSai::processBulkEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _In_ sai_common_api_t api, + _In_ const std::vector>& attributes, + _In_ const std::vector>& strAttributes) +{ + SWSS_LOG_ENTER(); + + auto info = sai_metadata_get_object_type_info(objectType); + + if (info->isobjectid) + { + SWSS_LOG_THROW("passing oid object to bulk non object id operation"); + } + + std::vector statuses(objectIds.size()); + + sai_status_t status = SAI_STATUS_SUCCESS; + + switch (api) + { + case SAI_COMMON_API_BULK_CREATE: + status = processBulkCreateEntry(objectType, objectIds, attributes, statuses); + break; + + case SAI_COMMON_API_BULK_REMOVE: + status = processBulkRemoveEntry(objectType, objectIds, statuses); + break; + + case SAI_COMMON_API_BULK_SET: + status = processBulkSetEntry(objectType, objectIds, attributes, statuses); + break; + + default: + SWSS_LOG_ERROR("api %s is not supported in bulk", sai_serialize_common_api(api).c_str()); + status = SAI_STATUS_NOT_SUPPORTED; + } + + std::vector oids(objectIds.size()); + + sendBulkApiResponse(api, status, (uint32_t)objectIds.size(), oids.data(), statuses.data()); + + return status; +} + +sai_status_t ServerSai::processBulkCreateEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _In_ const std::vector>& attributes, + _Out_ std::vector& statuses) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = SAI_STATUS_SUCCESS; + + uint32_t object_count = (uint32_t) objectIds.size(); + + sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR; + + std::vector attr_counts(object_count); + std::vector attr_lists(object_count); + + for (uint32_t idx = 0; idx < object_count; idx++) + { + attr_counts[idx] = attributes[idx]->get_attr_count(); + attr_lists[idx] = attributes[idx]->get_attr_list(); + } + + switch (objectType) + { + case SAI_OBJECT_TYPE_ROUTE_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_route_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkCreate( + object_count, + entries.data(), + attr_counts.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_FDB_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_fdb_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkCreate( + object_count, + entries.data(), + attr_counts.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_NAT_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_nat_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkCreate( + object_count, + entries.data(), + attr_counts.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_INSEG_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_inseg_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkCreate( + object_count, + entries.data(), + attr_counts.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + default: + return SAI_STATUS_NOT_SUPPORTED; + } + + return status; +} + +sai_status_t ServerSai::processBulkRemoveEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _Out_ std::vector& statuses) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = SAI_STATUS_SUCCESS; + + uint32_t object_count = (uint32_t) objectIds.size(); + + sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR; + + switch (objectType) + { + case SAI_OBJECT_TYPE_ROUTE_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_route_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkRemove( + object_count, + entries.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_FDB_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_fdb_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkRemove( + object_count, + entries.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_NAT_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_nat_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkRemove( + object_count, + entries.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_INSEG_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_inseg_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkRemove( + object_count, + entries.data(), + mode, + statuses.data()); + + } + break; + + default: + return SAI_STATUS_NOT_SUPPORTED; + } + + return status; +} + +sai_status_t ServerSai::processBulkSetEntry( + _In_ sai_object_type_t objectType, + _In_ const std::vector& objectIds, + _In_ const std::vector>& attributes, + _Out_ std::vector& statuses) +{ + SWSS_LOG_ENTER(); + + sai_status_t status = SAI_STATUS_SUCCESS; + + std::vector attr_lists; + + uint32_t object_count = (uint32_t) objectIds.size(); + + sai_bulk_op_error_mode_t mode = SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR; + + for (uint32_t it = 0; it < object_count; it++) + { + attr_lists.push_back(attributes[it]->get_attr_list()[0]); + } + + switch (objectType) + { + case SAI_OBJECT_TYPE_ROUTE_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_route_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkSet( + object_count, + entries.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_FDB_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_fdb_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkSet( + object_count, + entries.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_NAT_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_nat_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkSet( + object_count, + entries.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + case SAI_OBJECT_TYPE_INSEG_ENTRY: + { + std::vector entries(object_count); + for (uint32_t it = 0; it < object_count; it++) + { + sai_deserialize_inseg_entry(objectIds[it], entries[it]); + } + + status = m_sai->bulkSet( + object_count, + entries.data(), + attr_lists.data(), + mode, + statuses.data()); + + } + break; + + default: + return SAI_STATUS_NOT_SUPPORTED; + } + + return status; +} + +void ServerSai::sendBulkApiResponse( + _In_ sai_common_api_t api, + _In_ sai_status_t status, + _In_ uint32_t object_count, + _In_ const sai_object_id_t* object_ids, + _In_ const sai_status_t* statuses) +{ + SWSS_LOG_ENTER(); + + switch (api) + { + case SAI_COMMON_API_BULK_CREATE: + case SAI_COMMON_API_BULK_REMOVE: + case SAI_COMMON_API_BULK_SET: + break; + + default: + SWSS_LOG_THROW("api %s not supported by this function", + sai_serialize_common_api(api).c_str()); + } + + std::vector entry; + + for (uint32_t idx = 0; idx < object_count; idx++) + { + entry.emplace_back(sai_serialize_status(statuses[idx]), ""); + } + + if (api == SAI_COMMON_API_BULK_CREATE) + { + // in case of bulk create api, we need to return oids values that was + // created to the client + + for (uint32_t idx = 0; idx < object_count; idx++) + { + entry.emplace_back("oid", sai_serialize_object_id(object_ids[idx])); + } + } + + std::string strStatus = sai_serialize_status(status); + + SWSS_LOG_INFO("sending response for %s api with status: %s", + sai_serialize_common_api(api).c_str(), + strStatus.c_str()); + + m_selectableChannel->set(strStatus, entry, REDIS_ASIC_STATE_COMMAND_GETRESPONSE); +} diff --git a/tests/testclient.cpp b/tests/testclient.cpp index 474923b7359e..47230ab4d58c 100644 --- a/tests/testclient.cpp +++ b/tests/testclient.cpp @@ -21,6 +21,8 @@ class TestClient void test_create_vlan(); + void test_bulk_create_vlan(); + private: int profileGetNextValue( @@ -190,6 +192,150 @@ void TestClient::test_create_vlan() ASSERT_SUCCESS(sai_api_uninitialize()); } +void TestClient::test_bulk_create_vlan() +{ + SWSS_LOG_ENTER(); + + m_profileMap.clear(); + + m_profileMap[SAI_REDIS_KEY_ENABLE_CLIENT] = "true"; // act as a client + + m_profileIter = m_profileMap.begin(); + + m_smt.profileGetValue = std::bind(&TestClient::profileGetValue, this, _1, _2); + m_smt.profileGetNextValue = std::bind(&TestClient::profileGetNextValue, this, _1, _2, _3); + + m_test_services = m_smt.getServiceMethodTable(); + + ASSERT_SUCCESS(sai_api_initialize(0, &m_test_services)); + + sai_switch_api_t* switch_api; + + ASSERT_SUCCESS(sai_api_query(SAI_API_SWITCH, (void**)&switch_api)); + + sai_attribute_t attr; + + // connect to existing switch + attr.id = SAI_SWITCH_ATTR_INIT_SWITCH; + attr.value.booldata = false; + + sai_object_id_t switch_id = SAI_NULL_OBJECT_ID; + + ASSERT_SUCCESS(switch_api->create_switch(&switch_id, 1, &attr)); + + ASSERT_TRUE(switch_id != SAI_NULL_OBJECT_ID); + + SWSS_LOG_NOTICE("switchId: %s", sai_serialize_object_id(switch_id).c_str()); + + attr.id = SAI_SWITCH_ATTR_DEFAULT_VIRTUAL_ROUTER_ID; + + ASSERT_SUCCESS(switch_api->get_switch_attribute(switch_id, 1, &attr)); + + SWSS_LOG_NOTICE("got VRID: %s", sai_serialize_object_id(attr.value.oid).c_str()); + + attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; + + ASSERT_SUCCESS(switch_api->get_switch_attribute(switch_id, 1, &attr)); + + sai_object_id_t bridge_id = attr.value.oid; + + sai_bridge_api_t* bridge_api; + + ASSERT_SUCCESS(sai_api_query(SAI_API_BRIDGE, (void**)&bridge_api)); + + sai_object_id_t ports[128]; + + attr.id = SAI_BRIDGE_ATTR_PORT_LIST; + attr.value.objlist.count = 128; + attr.value.objlist.list = ports; + + ASSERT_SUCCESS(bridge_api->get_bridge_attribute(bridge_id, 1, &attr)); + + sai_vlan_api_t* vlan_api; + + ASSERT_SUCCESS(sai_api_query(SAI_API_VLAN, (void**)&vlan_api)); + + // create vlan + + attr.id = SAI_VLAN_ATTR_VLAN_ID; + attr.value.u16 = 200; + + sai_object_id_t vlan_id; + + ASSERT_SUCCESS(vlan_api->create_vlan(&vlan_id, switch_id, 1, &attr)); + + ASSERT_TRUE(vlan_id != SAI_NULL_OBJECT_ID); + + // bulk create vlan members + + uint32_t attr_count[2] = { 2, 2 }; + + const sai_attribute_t* attr_list[2]; + + sai_attribute_t attr0[2]; + + attr0[0].id = SAI_VLAN_MEMBER_ATTR_VLAN_ID; + attr0[0].value.oid = vlan_id; + + attr0[1].id = SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID; + attr0[1].value.oid = ports[0]; + + attr_list[0] = attr0; + + sai_attribute_t attr1[2]; + + attr1[0].id = SAI_VLAN_MEMBER_ATTR_VLAN_ID; + attr1[0].value.oid = vlan_id; + + attr1[1].id = SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID; + attr1[1].value.oid = ports[1]; + + attr_list[1] = attr1; + + sai_object_id_t members[2] = { SAI_NULL_OBJECT_ID, SAI_NULL_OBJECT_ID }; + sai_status_t statuses[2]; + + auto status = vlan_api->create_vlan_members( + switch_id, + 2, + attr_count, + attr_list, + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, + members, + statuses); + + ASSERT_SUCCESS(status); + + ASSERT_SUCCESS(statuses[0]); + ASSERT_SUCCESS(statuses[1]); + + ASSERT_TRUE(members[0] != SAI_NULL_OBJECT_ID); + ASSERT_TRUE(members[1] != SAI_NULL_OBJECT_ID); + + SWSS_LOG_NOTICE("members: %s, %s", + sai_serialize_object_id(members[0]).c_str(), + sai_serialize_object_id(members[1]).c_str()); + + // bulk remove vlan members + + status = vlan_api->remove_vlan_members( + 2, + members, + SAI_BULK_OP_ERROR_MODE_IGNORE_ERROR, + statuses); + + ASSERT_SUCCESS(status); + + ASSERT_SUCCESS(statuses[0]); + ASSERT_SUCCESS(statuses[1]); + + // remove vlan + + ASSERT_SUCCESS(vlan_api->remove_vlan(vlan_id)); + + ASSERT_SUCCESS(sai_api_uninitialize()); +} + int main() { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); @@ -202,5 +348,7 @@ int main() tc.test_create_vlan(); + tc.test_bulk_create_vlan(); + return EXIT_SUCCESS; }