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"); } }
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); }
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 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 {