int main() { swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); SWSS_LOG_ENTER(); // swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_INFO); try { test_sai_initialize(); test_enable_recording(); test_bulk_next_hop_group_member_create(); test_bulk_fdb_create(); test_bulk_route_set(); sai_api_uninitialize(); printf("\n[ %s ]\n\n", sai_serialize_status(SAI_STATUS_SUCCESS).c_str()); } catch (const std::exception &e) { SWSS_LOG_ERROR("exception: %s", e.what()); printf("\n[ %s ]\n\n%s\n\n", sai_serialize_status(SAI_STATUS_FAILURE).c_str(), e.what()); exit(EXIT_FAILURE); } return 0; }
void init_switch_BCM56850( _In_ sai_object_id_t switch_id) { SWSS_LOG_ENTER(); if (switch_id == SAI_NULL_OBJECT_ID) { SWSS_LOG_THROW("init switch with NULL switch id is not allowed"); } if (g_switch_state_map.find(switch_id) != g_switch_state_map.end()) { SWSS_LOG_THROW("switch already exists 0x%lx", switch_id); } ss = g_switch_state_map[switch_id] = std::make_shared<SwitchState>(switch_id); sai_status_t status = initialize_default_objects(); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_THROW("unable to init switch %s", sai_serialize_status(status).c_str()); } SWSS_LOG_NOTICE("initialized switch 0x%lx", switch_id); }
sai_status_t handle_bulk_route( _In_ const std::vector<std::string> &object_ids, _In_ sai_common_api_t api, _In_ const std::vector<std::shared_ptr<SaiAttributeList>> &attributes, _In_ const std::vector<sai_status_t> &recorded_statuses) { SWSS_LOG_ENTER(); std::vector<sai_route_entry_t> routes; for (size_t i = 0; i < object_ids.size(); ++i) { sai_route_entry_t route_entry; sai_deserialize_route_entry(object_ids[i], route_entry); route_entry.vr_id = translate_local_to_redis(route_entry.vr_id); routes.push_back(route_entry); SWSS_LOG_DEBUG("route: %s", object_ids[i].c_str()); } std::vector<sai_status_t> statuses; statuses.resize(recorded_statuses.size()); if (api == (sai_common_api_t)SAI_COMMON_API_BULK_SET) { /* * TODO: since SDK don't support bulk route api yet, we just use our * implementation, and later on we can switch to SDK api. * * TODO: we need to get operation type from recording, currently is not * serialized and it is hard coded here. */ std::vector<sai_attribute_t> attrs; for (const auto &a: attributes) { /* * Set has only 1 attribute, so we can just join them nicely here. */ attrs.push_back(a->get_attr_list()[0]); } sai_status_t status = sai_bulk_set_route_entry_attribute( (uint32_t)routes.size(), routes.data(), attrs.data(), SAI_BULK_OP_TYPE_INGORE_ERROR, // TODO we need to get that from recording statuses.data()); if (status != SAI_STATUS_SUCCESS) { /* * Entire API failes, so no need to compare statuses. */ return status; } for (size_t i = 0; i < statuses.size(); ++i) { if (statuses[i] != recorded_statuses[i]) { /* * If recorded statuses are different than received, throw * excetion since data don't match. */ SWSS_LOG_THROW("recorded status is %s but returned is %s on %s", sai_serialize_status(recorded_statuses[i]).c_str(), sai_serialize_status(statuses[i]).c_str(), object_ids[i].c_str()); } } return status; } else { SWSS_LOG_THROW("api %d is not supported in bulk route", api); } }
void performNotifySyncd(const std::string& request, const std::string response) { SWSS_LOG_ENTER(); // timestamp|action|data auto r = swss::tokenize(request, '|'); auto R = swss::tokenize(response, '|'); if (r[1] != "a" || R[1] != "A") { SWSS_LOG_THROW("invalid syncd notify request/response %s/%s", request.c_str(), response.c_str()); } if (g_notifySyncd == false) { SWSS_LOG_NOTICE("skipping notify syncd, selected by user"); return; } // tell syncd that we are compiling new view sai_attribute_t attr; attr.id = SAI_REDIS_SWITCH_ATTR_NOTIFY_SYNCD; const std::string requestAction = r[2]; if (requestAction == SYNCD_INIT_VIEW) { attr.value.s32 = SAI_REDIS_NOTIFY_SYNCD_INIT_VIEW; } else if (requestAction == SYNCD_APPLY_VIEW) { attr.value.s32 = SAI_REDIS_NOTIFY_SYNCD_APPLY_VIEW; } else { SWSS_LOG_THROW("invalid syncd notify request: %s", request.c_str()); } /* * NOTE: We don't need actual switch to set those attributes. */ sai_object_id_t switch_id = SAI_NULL_OBJECT_ID; sai_status_t status = sai_metadata_sai_switch_api->set_switch_attribute(switch_id, &attr); const std::string& responseStatus = R[2]; sai_status_t response_status; sai_deserialize_status(responseStatus, response_status); if (status != response_status) { SWSS_LOG_THROW("response status %s is different than syncd status %s", responseStatus.c_str(), sai_serialize_status(status).c_str()); } if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_THROW("failed to notify syncd %s", sai_serialize_status(status).c_str()); } // OK }
sai_status_t handle_generic( _In_ sai_object_type_t object_type, _In_ const std::string &str_object_id, _In_ sai_common_api_t api, _In_ uint32_t attr_count, _In_ sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); sai_object_id_t local_id; sai_deserialize_object_id(str_object_id, local_id); SWSS_LOG_DEBUG("generic %s for %s:%s", sai_serialize_common_api(api).c_str(), sai_serialize_object_type(object_type).c_str(), str_object_id.c_str()); auto info = sai_metadata_get_object_type_info(object_type); sai_object_meta_key_t meta_key; meta_key.objecttype = object_type; switch (api) { case SAI_COMMON_API_CREATE: { sai_object_id_t switch_id = sai_switch_id_query(local_id); if (switch_id == SAI_NULL_OBJECT_ID) { SWSS_LOG_THROW("invalid switch_id translated from VID %s", sai_serialize_object_id(local_id).c_str()); } if (object_type == SAI_OBJECT_TYPE_SWITCH) { update_notifications_pointers(attr_count, attr_list); /* * We are creating switch, in both cases local and redis * switch id is deterministic and should be the same. */ } else { /* * When we creating switch, then switch_id parameter is * ignored, but we can't convert it using vid to rid map, * since rid don't exist yet, so skip translate for switch, * but use translate for all other objects. */ switch_id = translate_local_to_redis(switch_id); } sai_status_t status = info->create(&meta_key, switch_id, attr_count, attr_list); if (status == SAI_STATUS_SUCCESS) { sai_object_id_t rid = meta_key.objectkey.key.object_id; match_redis_with_rec(rid, local_id); SWSS_LOG_INFO("saved VID %s to RID %s", sai_serialize_object_id(local_id).c_str(), sai_serialize_object_id(rid).c_str()); } else { SWSS_LOG_ERROR("failed to create %s", sai_serialize_status(status).c_str()); } return status; } case SAI_COMMON_API_REMOVE: { meta_key.objectkey.key.object_id = translate_local_to_redis(local_id); return info->remove(&meta_key); } case SAI_COMMON_API_SET: { if (object_type == SAI_OBJECT_TYPE_SWITCH) { update_notifications_pointers(1, attr_list); } meta_key.objectkey.key.object_id = translate_local_to_redis(local_id); return info->set(&meta_key, attr_list); } case SAI_COMMON_API_GET: { meta_key.objectkey.key.object_id = translate_local_to_redis(local_id); return info->get(&meta_key, attr_count, attr_list); } default: SWSS_LOG_THROW("generic other apis not implemented"); } }
int replay(int argc, char **argv) { //swss::Logger::getInstance().setMinPrio(swss::Logger::SWSS_DEBUG); SWSS_LOG_ENTER(); if (argc < 2) { fprintf(stderr, "ERR: need to specify filename\n"); return -1; } char* filename = argv[argc - 1]; SWSS_LOG_NOTICE("using file: %s", filename); std::ifstream infile(filename); if (!infile.is_open()) { SWSS_LOG_ERROR("failed to open file %s", filename); return -1; } std::string line; while (std::getline(infile, line)) { // std::cout << "processing " << line << std::endl; sai_common_api_t api = SAI_COMMON_API_CREATE; auto p = line.find_first_of("|"); char op = line[p+1]; switch (op) { case 'a': { std::string response; do { // this line may be notification, we need to skip if (!std::getline(infile, response)) { SWSS_LOG_THROW("failed to read next file from file, previous: %s", line.c_str()); } } while (response[response.find_first_of("|") + 1] == 'n'); performNotifySyncd(line, response); } continue; case '@': performSleep(line); continue; case 'c': api = SAI_COMMON_API_CREATE; break; case 'r': api = SAI_COMMON_API_REMOVE; break; case 's': api = SAI_COMMON_API_SET; break; case 'S': processBulk((sai_common_api_t)SAI_COMMON_API_BULK_SET, line); continue; case 'g': api = SAI_COMMON_API_GET; break; case '#': case 'n': continue; // skip comment and notification default: SWSS_LOG_THROW("unknown op %c on line %s", op, line.c_str()); } // timestamp|action|objecttype:objectid|attrid=value,... auto fields = swss::tokenize(line, '|'); // objecttype:objectid (object id may contain ':') auto start = fields[2].find_first_of(":"); auto str_object_type = fields[2].substr(0, start); auto str_object_id = fields[2].substr(start + 1); sai_object_type_t object_type = deserialize_object_type(str_object_type); auto values = get_values(fields); SaiAttributeList list(object_type, values, false); sai_attribute_t *attr_list = list.get_attr_list(); uint32_t attr_count = list.get_attr_count(); SWSS_LOG_DEBUG("attr count: %u", list.get_attr_count()); if (api != SAI_COMMON_API_GET) { translate_local_to_redis(object_type, attr_count, attr_list); } sai_status_t status; auto info = sai_metadata_get_object_type_info(object_type); switch (object_type) { case SAI_OBJECT_TYPE_FDB_ENTRY: status = handle_fdb(str_object_id, api, attr_count, attr_list); break; case SAI_OBJECT_TYPE_NEIGHBOR_ENTRY: status = handle_neighbor(str_object_id, api, attr_count, attr_list); break; case SAI_OBJECT_TYPE_ROUTE_ENTRY: status = handle_route(str_object_id, api, attr_count, attr_list); break; default: if (info->isnonobjectid) { SWSS_LOG_THROW("object %s:%s is non object id, but not handled, FIXME", sai_serialize_object_type(object_type).c_str(), str_object_id.c_str()); } status = handle_generic(object_type, str_object_id, api, attr_count, attr_list); break; } if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_THROW("failed to execute api: %c: %s", op, sai_serialize_status(status).c_str()); } if (api == SAI_COMMON_API_GET) { std::string response; do { // this line may be notification, we need to skip std::getline(infile, response); } while (response[response.find_first_of("|") + 1] == 'n'); try { handle_get_response(object_type, attr_count, attr_list, response); } catch (const std::exception &e) { SWSS_LOG_NOTICE("line: %s", line.c_str()); SWSS_LOG_NOTICE("resp: %s", response.c_str()); exit(EXIT_FAILURE); } } } infile.close(); SWSS_LOG_NOTICE("finished replaying %s with SUCCESS", filename); return 0; }
void channelOpSetReadOnlyAttribute( _In_ const std::string &key, _In_ const std::vector<swss::FieldValueTuple> &values) { SWSS_LOG_ENTER(); for (const auto &v: values) { SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str()); } if (values.size() != 1) { SWSS_LOG_ERROR("expected 1 value only, but given: %zu", values.size()); return; } const std::string &str_object_type = key.substr(0, key.find(":")); const std::string &str_object_id = key.substr(key.find(":") + 1); sai_object_type_t object_type; sai_deserialize_object_type(str_object_type, object_type); if (object_type == SAI_OBJECT_TYPE_NULL || object_type >= SAI_OBJECT_TYPE_EXTENSIONS_MAX) { SWSS_LOG_ERROR("invalid object type: %d", object_type); return; } auto info = sai_metadata_get_object_type_info(object_type); if (info->isnonobjectid) { SWSS_LOG_ERROR("non object id %s is not supported yet", str_object_type.c_str()); return; } sai_object_id_t object_id; sai_deserialize_object_id(str_object_id, object_id); sai_object_type_t ot = sai_object_type_query(object_id); if (ot != object_type) { SWSS_LOG_ERROR("object type is differnt than provided %s, but oid is %s", str_object_type.c_str(), sai_serialize_object_type(ot).c_str()); return; } sai_object_id_t switch_id = sai_switch_id_query(object_id); if (switch_id == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("failed to find switch id for oid %s", str_object_id.c_str()); return; } // oid is validated and we got switch id const std::string &str_attr_id = fvField(values.at(0)); const std::string &str_attr_value = fvValue(values.at(0)); auto meta = sai_metadata_get_attr_metadata_by_attr_id_name(str_attr_id.c_str()); if (meta == NULL) { SWSS_LOG_ERROR("failed to find attr %s", str_attr_id.c_str()); return; } if (meta->objecttype != ot) { SWSS_LOG_ERROR("attr %s belongs to differnt object type than oid: %s", str_attr_id.c_str(), sai_serialize_object_type(ot).c_str()); return; } // we got attr metadata sai_attribute_t attr; attr.id = meta->attrid; sai_deserialize_attr_value(str_attr_value, *meta, attr); SWSS_LOG_NOTICE("switch id is %s", sai_serialize_object_id(switch_id).c_str()); sai_status_t status = meta_unittests_allow_readonly_set_once(meta->objecttype, meta->attrid); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to enable SET readonly attribute once: %s", sai_serialize_status(status).c_str()); return; } sai_object_meta_key_t meta_key = { .objecttype = ot, .objectkey = { .key = { .object_id = object_id } } }; status = info->set(&meta_key, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to set %s to %s on %s", str_attr_id.c_str(), str_attr_value.c_str(), str_object_id.c_str()); } else { SWSS_LOG_NOTICE("SUCCESS to set %s to %s on %s", str_attr_id.c_str(), str_attr_value.c_str(), str_object_id.c_str()); } sai_deserialize_free_attribute_value(meta->attrvaluetype, attr); }
void handleUnittestChannelOp( _In_ const std::string &op, _In_ const std::string &key, _In_ const std::vector<swss::FieldValueTuple> &values) { /* * Since we will access and modify DB we need to be under mutex. * * NOTE: since this unittest channel is handled in thread, then that means * there is a DELAY from producer and consumer thread in VS, so if user * will set value on the specific READ_ONLY value he should wait for some * time until that value will be propagated to virtual switch. */ MUTEX(); SWSS_LOG_ENTER(); SWSS_LOG_NOTICE("read only SET: op = %s, key = %s", op.c_str(), key.c_str()); if (op == SAI_VS_UNITTEST_ENABLE_UNITTESTS) { bool enable = (key == "true"); meta_unittests_enable(enable); } else if (op == SAI_VS_UNITTEST_SET_RO_OP) { for (const auto &v: values) { SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str()); } if (values.size() != 1) { SWSS_LOG_ERROR("expected 1 value only, but given: %zu", values.size()); return; } const std::string &str_object_type = key.substr(0, key.find(":")); const std::string &str_object_id = key.substr(key.find(":") + 1); sai_object_type_t object_type; sai_deserialize_object_type(str_object_type, object_type); if (object_type == SAI_OBJECT_TYPE_NULL || object_type >= SAI_OBJECT_TYPE_MAX) { SWSS_LOG_ERROR("invalid object type: %d", object_type); return; } auto info = sai_metadata_get_object_type_info(object_type); if (info->isnonobjectid) { SWSS_LOG_ERROR("non object id %s is not supported yet", str_object_type.c_str()); return; } sai_object_id_t object_id; sai_deserialize_object_id(str_object_id, object_id); sai_object_type_t ot = sai_object_type_query(object_id); if (ot != object_type) { SWSS_LOG_ERROR("object type is differnt than provided %s, but oid is %s", str_object_type.c_str(), sai_serialize_object_type(ot).c_str()); return; } sai_object_id_t switch_id = sai_switch_id_query(object_id); if (switch_id == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("failed to find switch id for oid %s", str_object_id.c_str()); return; } // oid is validated and we got switch id const std::string &str_attr_id = fvField(values.at(0)); const std::string &str_attr_value = fvValue(values.at(0)); auto meta = sai_metadata_get_attr_metadata_by_attr_id_name(str_attr_id.c_str()); if (meta == NULL) { SWSS_LOG_ERROR("failed to find attr %s", str_attr_id.c_str()); return; } if (meta->objecttype != ot) { SWSS_LOG_ERROR("attr %s belongs to differnt object type than oid: %s", str_attr_id.c_str(), sai_serialize_object_type(ot).c_str()); return; } // we got attr metadata sai_attribute_t attr; attr.id = meta->attrid; sai_deserialize_attr_value(str_attr_value, *meta, attr); SWSS_LOG_NOTICE("switch id is %s", sai_serialize_object_id(switch_id).c_str()); sai_status_t status = meta_unittests_allow_readonly_set_once(meta->objecttype, meta->attrid); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to enable SET readonly attribute once: %s", sai_serialize_status(status).c_str()); return; } sai_object_meta_key_t meta_key = { .objecttype = ot, .objectkey = { .key = { .object_id = object_id } } }; status = info->set(&meta_key, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to set %s to %s on %s", str_attr_id.c_str(), str_attr_value.c_str(), str_object_id.c_str()); } else { SWSS_LOG_NOTICE("SUCCESS to set %s to %s on %s", str_attr_id.c_str(), str_attr_value.c_str(), str_object_id.c_str()); } sai_deserialize_free_attribute_value(meta->attrvaluetype, attr); } else {
sai_status_t internal_vs_generic_get( _In_ sai_object_type_t object_type, _In_ const std::string &serialized_object_id, _In_ sai_object_id_t switch_id, _In_ uint32_t attr_count, _Out_ sai_attribute_t *attr_list) { SWSS_LOG_ENTER(); auto &objectHash = g_switch_state_map.at(switch_id)->objectHash.at(object_type); auto it = objectHash.find(serialized_object_id); if (it == objectHash.end()) { SWSS_LOG_ERROR("not found %s:%s", sai_serialize_object_type(object_type).c_str(), serialized_object_id.c_str()); return SAI_STATUS_ITEM_NOT_FOUND; } /* * We need reference here since we can potentially update attr hash for RO * object. */ AttrHash& attrHash = it->second; /* * Some of the list query maybe for length, so we can't do * normal serialize, maybe with count only. */ sai_status_t final_status = SAI_STATUS_SUCCESS; for (uint32_t idx = 0; idx < attr_count; ++idx) { sai_attr_id_t id = attr_list[idx].id; auto meta = sai_metadata_get_attr_metadata(object_type, id); if (meta == NULL) { SWSS_LOG_ERROR("failed to find attribute %d for %s:%s", id, sai_serialize_object_type(object_type).c_str(), serialized_object_id.c_str()); return SAI_STATUS_FAILURE; } sai_status_t status; if (HAS_FLAG_READ_ONLY(meta->flags)) { /* * Read only attributes may require recalculation. * Metadata makes sure that non object id's can't have * read only attributes. So here is defenetly OID. */ sai_object_id_t oid; sai_deserialize_object_id(serialized_object_id, oid); status = refresh_read_only(meta, oid, switch_id); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("%s read only not implemented on %s", meta->attridname, serialized_object_id.c_str()); return status; } } auto ait = attrHash.find(meta->attridname); if (ait == attrHash.end()) { SWSS_LOG_ERROR("%s not implemented on %s", meta->attridname, serialized_object_id.c_str()); return SAI_STATUS_NOT_IMPLEMENTED; } auto attr = ait->second->getAttr(); status = transfer_attributes(object_type, 1, attr, &attr_list[idx], false); if (status == SAI_STATUS_BUFFER_OVERFLOW) { /* * This is considered partial success, since we get correct list * length. Note that other items ARE processes on the list. */ SWSS_LOG_NOTICE("BUFFER_OVERFLOW %s: %s", serialized_object_id.c_str(), meta->attridname); /* * We still continue processing other attributes for get as long as * we only will be getting buffer overflow error. */ final_status = status; continue; } if (status != SAI_STATUS_SUCCESS) { // all other errors SWSS_LOG_ERROR("get failed %s: %s: %s", serialized_object_id.c_str(), meta->attridname, sai_serialize_status(status).c_str()); return status; } } return final_status; }