sai_object_id_t translate_rid_to_vid( _In_ sai_object_id_t rid) { SWSS_LOG_ENTER(); if (rid == SAI_NULL_OBJECT_ID) { SWSS_LOG_DEBUG("translated RID null to VID null"); return SAI_NULL_OBJECT_ID; } sai_object_id_t vid; std::string str_rid; std::string str_vid; sai_serialize_primitive(rid, str_rid); auto pvid = g_redisClient->hget(RIDTOVID, str_rid); if (pvid != NULL) { // object exists str_vid = *pvid; int index = 0; sai_deserialize_primitive(str_vid, index, vid); SWSS_LOG_DEBUG("translated RID %llx to VID %llx", rid, vid); return vid; } SWSS_LOG_INFO("spotted new RID %llx", rid); sai_object_type_t object_type = sai_object_type_query(rid); if (object_type == SAI_OBJECT_TYPE_NULL) { SWSS_LOG_ERROR("sai_object_type_query returned NULL type for RID %llx", rid); exit(EXIT_FAILURE); } vid = redis_create_virtual_object_id(object_type); SWSS_LOG_DEBUG("translated RID %llx to VID %llx", rid, vid); sai_serialize_primitive(vid, str_vid); g_redisClient->hset(RIDTOVID, str_rid, str_vid); g_redisClient->hset(VIDTORID, str_vid, str_rid); return vid; }
static sai_status_t create_vlan_members() { SWSS_LOG_ENTER(); sai_object_id_t switch_id = ss->getSwitchId(); /* * Crete vlan members for bridge ports. */ for (auto bridge_port_id: bridge_port_list_port_based) { SWSS_LOG_DEBUG("create vlan member for bridge port %s", sai_serialize_object_id(bridge_port_id).c_str()); sai_attribute_t attrs[3]; attrs[0].id = SAI_VLAN_MEMBER_ATTR_BRIDGE_PORT_ID; attrs[0].value.oid = bridge_port_id; attrs[1].id = SAI_VLAN_MEMBER_ATTR_VLAN_ID; attrs[1].value.oid = default_vlan_id; attrs[2].id = SAI_VLAN_MEMBER_ATTR_VLAN_TAGGING_MODE; attrs[2].value.s32 = SAI_VLAN_TAGGING_MODE_UNTAGGED; sai_object_id_t vlan_member_id; CHECK_STATUS(vs_generic_create(SAI_OBJECT_TYPE_VLAN_MEMBER, &vlan_member_id, switch_id, 3, attrs)); } return SAI_STATUS_SUCCESS; }
void swss::NotificationConsumer::processReply(redisReply *reply) { SWSS_LOG_ENTER(); if (reply->type != REDIS_REPLY_ARRAY) { SWSS_LOG_ERROR("expected ARRAY redis reply on channel %s, got: %d", m_channel.c_str(), reply->type); throw std::runtime_error("getRedisReply operation failed"); } if (reply->elements != REDIS_PUBLISH_MESSAGE_ELEMNTS) { SWSS_LOG_ERROR("expected %d elements in redis reply on channel %s, got: %zu", REDIS_PUBLISH_MESSAGE_ELEMNTS, m_channel.c_str(), reply->elements); throw std::runtime_error("getRedisReply operation failed"); } std::string msg = std::string(reply->element[REDIS_PUBLISH_MESSAGE_INDEX]->str); SWSS_LOG_DEBUG("got message: %s", msg.c_str()); m_queue.push(msg); }
sai_status_t handle_route( _In_ 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(); int index = 0; sai_unicast_route_entry_t route_entry; sai_deserialize_route_entry(str_object_id, index, route_entry); route_entry.vr_id = translate_vid_to_rid(route_entry.vr_id); SWSS_LOG_DEBUG("route: %s", str_object_id.c_str()); switch(api) { case SAI_COMMON_API_CREATE: return sai_route_api->create_route(&route_entry, attr_count, attr_list); case SAI_COMMON_API_REMOVE: return sai_route_api->remove_route(&route_entry); case SAI_COMMON_API_SET: return sai_route_api->set_route_attribute(&route_entry, attr_list); case SAI_COMMON_API_GET: return sai_route_api->get_route_attribute(&route_entry, attr_count, attr_list); default: SWSS_LOG_ERROR("route other apis not implemented"); exit(EXIT_FAILURE); } }
void handle_get_response( sai_object_type_t object_type, uint32_t get_attr_count, sai_attribute_t* get_attr_list, const std::string& response) { SWSS_LOG_ENTER(); //std::cout << "processing " << response << std::endl; // timestamp|action|objecttype:objectid|attrid=value,... auto v = swss::tokenize(response, '|'); auto values = get_values(v); SaiAttributeList list(object_type, values, false); sai_attribute_t *attr_list = list.get_attr_list(); uint32_t attr_count = list.get_attr_count(); match_list_lengths(object_type, get_attr_count, get_attr_list, attr_count, attr_list); SWSS_LOG_DEBUG("list match"); match_redis_with_rec(object_type, get_attr_count, get_attr_list, attr_count, attr_list); // NOTE: Primitive values are not matched (recording vs switch/vs), we can add that check }
std::unordered_map<sai_uint32_t, sai_object_id_t> redisGetLaneMap() { SWSS_LOG_ENTER(); auto hash = g_redisClient->hgetall(LANES); SWSS_LOG_DEBUG("previous lanes: %lu", hash.size()); std::unordered_map<sai_uint32_t, sai_object_id_t> map; for (auto &kv: hash) { const std::string &str_key = kv.first; const std::string &str_value = kv.second; sai_uint32_t lane; sai_object_id_t portId; int index = 0; sai_deserialize_primitive(str_key, index, lane); index = 0; sai_deserialize_primitive(str_value, index, portId); map[lane] = portId; } return map; }
/** * Routine Description: * @brief Internal set attribute * * Arguments: * @param[in] object_type - type of object * @param[in] serialized_object_id - serialized object id * @param[in] attr - attribute to serialize * * Return Values: * @return SAI_STATUS_SUCCESS on success * Failure status code on error */ sai_status_t internal_redis_generic_set( _In_ sai_object_type_t object_type, _In_ const std::string &serialized_object_id, _In_ const sai_attribute_t *attr) { std::lock_guard<std::mutex> lock(g_mutex); SWSS_LOG_ENTER(); std::vector<swss::FieldValueTuple> entry = SaiAttributeList::serialize_attr_list( object_type, 1, attr, false); std::string str_object_type; sai_serialize_primitive(object_type, str_object_type); std::string key = str_object_type + ":" + serialized_object_id; SWSS_LOG_DEBUG("generic set key: %s, fields: %lu", key.c_str(), entry.size()); g_asicState->set(key, entry, "set"); return SAI_STATUS_SUCCESS; }
bool handleRestartQuery(swss::NotificationConsumer &restartQuery) { SWSS_LOG_ENTER(); std::string op; std::string data; std::vector<swss::FieldValueTuple> values; restartQuery.pop(op, data, values); SWSS_LOG_DEBUG("op = %d", op.c_str()); if (op == "COLD") { SWSS_LOG_NOTICE("received COLD switch shutdown event"); return false; } if (op == "WARM") { SWSS_LOG_NOTICE("received WARM switch shutdown event"); return true; } SWSS_LOG_WARN("received '%s' unknown switch shutdown event, assuming COLD", op.c_str()); return false; }
static sai_status_t create_bridge_ports() { SWSS_LOG_ENTER(); sai_object_id_t switch_id = ss->getSwitchId(); /* * Create bridge port for 1q router. */ sai_attribute_t attr; attr.id = SAI_BRIDGE_PORT_ATTR_TYPE; attr.value.s32 = SAI_BRIDGE_PORT_TYPE_1Q_ROUTER; CHECK_STATUS(vs_generic_create(SAI_OBJECT_TYPE_BRIDGE_PORT, &default_bridge_port_1q_router, ss->getSwitchId(), 1, &attr)); attr.id = SAI_SWITCH_ATTR_DEFAULT_1Q_BRIDGE_ID; CHECK_STATUS(vs_generic_get(SAI_OBJECT_TYPE_SWITCH, switch_id, 1, &attr)); /* * Create bridge ports for regular ports. */ sai_object_id_t default_1q_bridge_id = attr.value.oid; bridge_port_list_port_based.clear(); for (const auto &port_id: port_list) { SWSS_LOG_DEBUG("create bridge port for port %s", sai_serialize_object_id(port_id).c_str()); sai_attribute_t attrs[4]; attrs[0].id = SAI_BRIDGE_PORT_ATTR_BRIDGE_ID; attrs[0].value.oid = default_1q_bridge_id; attrs[1].id = SAI_BRIDGE_PORT_ATTR_FDB_LEARNING_MODE; attrs[1].value.s32 = SAI_BRIDGE_PORT_FDB_LEARNING_MODE_HW; attrs[2].id = SAI_BRIDGE_PORT_ATTR_PORT_ID; attrs[2].value.oid = port_id; attrs[3].id = SAI_BRIDGE_PORT_ATTR_TYPE; attrs[3].value.s32 = SAI_BRIDGE_PORT_TYPE_PORT; sai_object_id_t bridge_port_id; CHECK_STATUS(vs_generic_create(SAI_OBJECT_TYPE_BRIDGE_PORT, &bridge_port_id, switch_id, 4, attrs)); bridge_port_list_port_based.push_back(bridge_port_id); } return SAI_STATUS_SUCCESS; }
sai_object_id_t redis_create_virtual_object_id( _In_ sai_object_type_t object_type) { SWSS_LOG_ENTER(); uint64_t virtual_id = g_redisClient->incr(VIDCOUNTER); sai_object_id_t vid = (((sai_object_id_t)object_type) << 48) | virtual_id; SWSS_LOG_DEBUG("created virtual object id %llx for object type %x", vid, object_type); return vid; }
void WatermarkOrch::clearSingleWm(Table *table, string wm_name, vector<sai_object_id_t> &obj_ids) { /* Zero-out some WM in some table for some vector of object ids*/ SWSS_LOG_ENTER(); SWSS_LOG_DEBUG("clear WM %s, for %ld obj ids", wm_name.c_str(), obj_ids.size()); vector<FieldValueTuple> vfvt = {{wm_name, "0"}}; for (sai_object_id_t id: obj_ids) { table->set(sai_serialize_object_id(id), vfvt); } }
void redisCreateRidAndVidMapping(sai_object_id_t rid, sai_object_id_t vid) { SWSS_LOG_ENTER(); std::string strRid, strVid; sai_serialize_primitive(rid, strRid); sai_serialize_primitive(vid, strVid); g_redisClient->hset(VIDTORID, strVid, strRid); g_redisClient->hset(RIDTOVID, strRid, strVid); SWSS_LOG_DEBUG("set VID %llx and RID %llx", vid, rid); }
sai_object_id_t translate_vid_to_rid( _In_ sai_object_id_t vid) { SWSS_LOG_ENTER(); if (vid == SAI_NULL_OBJECT_ID) { SWSS_LOG_DEBUG("translated RID null to VID null"); return SAI_NULL_OBJECT_ID; } std::string str_vid; sai_serialize_primitive(vid, str_vid); std::string str_rid; auto prid = g_redisClient->hget(VIDTORID, str_vid); if (prid == NULL) { SWSS_LOG_ERROR("unable to get RID for VID: %s", str_vid.c_str()); exit(EXIT_FAILURE); } str_rid = *prid; sai_object_id_t rid; int index = 0; sai_deserialize_primitive(str_rid, index, rid); SWSS_LOG_DEBUG("translated VID %llx to RID %llx", vid, rid); return rid; }
void unittestChannelThreadProc() { SWSS_LOG_ENTER(); SWSS_LOG_NOTICE("enter VS unittest channel thread"); swss::Select s; s.addSelectable(g_unittestChannelNotificationConsumer.get()); s.addSelectable(&g_unittestChannelThreadEvent); while (g_unittestChannelRun) { swss::Selectable *sel; int result = s.select(&sel); if (sel == &g_unittestChannelThreadEvent) { // user requested shutdown_switch break; } if (result == swss::Select::OBJECT) { swss::KeyOpFieldsValuesTuple kco; std::string op; std::string data; std::vector<swss::FieldValueTuple> values; g_unittestChannelNotificationConsumer->pop(op, data, values); SWSS_LOG_DEBUG("notification: op = %s, data = %s", op.c_str(), data.c_str()); try { handleUnittestChannelOp(op, data, values); } catch (const std::exception &e) { SWSS_LOG_ERROR("Exception: op = %s, data = %s, %s", op.c_str(), data.c_str(), e.what()); } } } SWSS_LOG_NOTICE("exit VS unittest channel thread"); }
void handleUnittestChannelOp( _In_ const std::string &op, _In_ const std::string &key, _In_ const std::vector<swss::FieldValueTuple> &values) { MUTEX(); SWSS_LOG_ENTER(); /* * 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. */ SWSS_LOG_NOTICE("op = %s, key = %s", op.c_str(), key.c_str()); for (const auto &v: values) { SWSS_LOG_DEBUG("attr: %s: %s", fvField(v).c_str(), fvValue(v).c_str()); } if (op == SAI_VS_UNITTEST_ENABLE_UNITTESTS) { channelOpEnableUnittests(key, values); } else if (op == SAI_VS_UNITTEST_SET_RO_OP) { channelOpSetReadOnlyAttribute(key, values); } else if (op == SAI_VS_UNITTEST_SET_STATS_OP) { channelOpSetStats(key, values); } else { SWSS_LOG_ERROR("unknown unittest operation: %s", op.c_str()); } }
sai_uint32_t saiGetPortCount() { SWSS_LOG_ENTER(); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_PORT_NUMBER; sai_status_t status = sai_switch_api->get_switch_attribute(1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to get port number: %d", status); exit(EXIT_FAILURE); } SWSS_LOG_DEBUG("port count is %u", attr.value.u32); return attr.value.u32; }
sai_status_t internal_redis_generic_remove( _In_ sai_object_type_t object_type, _In_ const std::string &serialized_object_id) { SWSS_LOG_ENTER(); std::string str_object_type = sai_serialize_object_type(object_type); std::string key = str_object_type + ":" + serialized_object_id; SWSS_LOG_DEBUG("generic remove key: %s", key.c_str()); if (g_record) { recordLine("r|" + key); } g_asicState->del(key, "remove"); return SAI_STATUS_SUCCESS; }
sai_object_id_t saiGetCpuId() { SWSS_LOG_ENTER(); sai_attribute_t attr; attr.id = SAI_SWITCH_ATTR_CPU_PORT; sai_status_t status = sai_switch_api->get_switch_attribute(1, &attr); if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_ERROR("failed to get cpu port: %d", status); exit(EXIT_FAILURE); } SWSS_LOG_DEBUG("cpu port RID %llx", attr.value.oid); return attr.value.oid; }
RedisReply::RedisReply(DBConnector *db, string command, int exepectedType, bool isFormatted) { SWSS_LOG_ENTER(); SWSS_LOG_DEBUG("Redis reply command: %s", command.c_str()); if (isFormatted) { redisAppendFormattedCommand(db->getContext(), command.c_str(), command.length()); redisGetReply(db->getContext(), (void**)&m_reply); } else { m_reply = (redisReply *)redisCommand(db->getContext(), command.c_str()); } if (!m_reply) { SWSS_LOG_ERROR("Redis reply is NULL, memory exception, command: %s", command.c_str()); throw system_error(make_error_code(errc::not_enough_memory), "Memory exception, reply is null"); } if (m_reply->type != exepectedType) { const char *err = (m_reply->type == REDIS_REPLY_STRING || m_reply->type == REDIS_REPLY_ERROR) ? m_reply->str : "NON-STRING-REPLY"; SWSS_LOG_ERROR("Expected to get redis type %d got type %d, command: %s, err: %s", exepectedType, m_reply->type, command.c_str(), err); freeReplyObject(m_reply); m_reply = NULL; /* Some compilers call destructor in this case */ throw system_error(make_error_code(errc::io_error), "Wrong expected type of result"); } }
sai_object_id_t translate_local_to_redis( _In_ sai_object_id_t rid) { SWSS_LOG_ENTER(); SWSS_LOG_DEBUG("translating local RID %s", sai_serialize_object_id(rid).c_str()); if (rid == SAI_NULL_OBJECT_ID) { return SAI_NULL_OBJECT_ID; } auto it = local_to_redis.find(rid); if (it == local_to_redis.end()) { SWSS_LOG_THROW("failed to translate local RID %s", sai_serialize_object_id(rid).c_str()); } return it->second; }
void swss::NotificationConsumer::readMe() { SWSS_LOG_ENTER(); redisReply *reply = NULL; if (redisGetReply(m_subscribe->getContext(), (void**)&reply) != REDIS_OK) { SWSS_LOG_ERROR("failed to read redis reply on channel %s", m_channel.c_str()); throw std::runtime_error("Unable to read redis reply"); } if (reply->type != REDIS_REPLY_ARRAY) { SWSS_LOG_ERROR("expected ARRAY redis reply on channel %s, got: %d", m_channel.c_str(), reply->type); throw std::runtime_error("getRedisReply operation failed"); } if (reply->elements != REDIS_PUBLISH_MESSAGE_ELEMNTS) { SWSS_LOG_ERROR("expected %d elements in redis reply on channel %s, got: %u", REDIS_PUBLISH_MESSAGE_ELEMNTS, m_channel.c_str(), reply->elements); throw std::runtime_error("getRedisReply operation failed"); } m_msg = std::string(reply->element[REDIS_PUBLISH_MESSAGE_INDEX]->str); SWSS_LOG_DEBUG("got message: %s", m_msg.c_str()); freeReplyObject(reply); }
void match_redis_with_rec( sai_object_id_t get_oid, sai_object_id_t oid) { SWSS_LOG_ENTER(); auto it = redis_to_local.find(get_oid); if (it == redis_to_local.end()) { redis_to_local[get_oid] = oid; local_to_redis[oid] = get_oid; } if (oid != redis_to_local[get_oid]) { SWSS_LOG_THROW("match failed, oid order is mismatch :( oid 0x%lx get_oid 0x%lx second 0x%lx", oid, get_oid, redis_to_local[get_oid]); } SWSS_LOG_DEBUG("map size: %zu", local_to_redis.size()); }
void processBulk( _In_ sai_common_api_t api, _In_ const std::string &line) { SWSS_LOG_ENTER(); if (!line.size()) { return; } if (api != (sai_common_api_t)SAI_COMMON_API_BULK_SET) { SWSS_LOG_THROW("bulk common api %d is not supported yet, FIXME", api); } /* * Here we know we have bulk SET api */ // timestamp|action|objecttype||objectid|attrid=value|...|status||objectid||objectid|attrid=value|...|status||... auto fields = tokenize(line, "||"); auto first = fields.at(0); // timestamp|acion|objecttype std::string str_object_type = swss::tokenize(first, '|').at(2); sai_object_type_t object_type = deserialize_object_type(str_object_type); std::vector<std::string> object_ids; std::vector<std::shared_ptr<SaiAttributeList>> attributes; std::vector<sai_status_t> statuses; for (size_t idx = 1; idx < fields.size(); ++idx) { // object_id|attr=value|...|status const std::string &joined = fields[idx]; auto split = swss::tokenize(joined, '|'); std::string str_object_id = split.front(); object_ids.push_back(str_object_id); std::string str_status = split.back(); sai_status_t status; sai_deserialize_status(str_status, status); statuses.push_back(status); std::vector<swss::FieldValueTuple> entries; // attributes per object id // skip front object_id and back status SWSS_LOG_DEBUG("processing: %s", joined.c_str()); for (size_t i = 1; i < split.size() - 1; ++i) { const auto &item = split[i]; auto start = item.find_first_of("="); auto field = item.substr(0, start); auto value = item.substr(start + 1); swss::FieldValueTuple entry(field, value); entries.push_back(entry); } // since now we converted this to proper list, we can extract attributes std::shared_ptr<SaiAttributeList> list = std::make_shared<SaiAttributeList>(object_type, entries, false); sai_attribute_t *attr_list = list->get_attr_list(); uint32_t attr_count = list->get_attr_count(); if (api != (sai_common_api_t)SAI_COMMON_API_BULK_GET) { translate_local_to_redis(object_type, attr_count, attr_list); } attributes.push_back(list); } sai_status_t status; switch (object_type) { case SAI_OBJECT_TYPE_ROUTE_ENTRY: status = handle_bulk_route(object_ids, api, attributes, statuses); break; default: SWSS_LOG_THROW("bulk op for %s is not supported yet, FIXME", sai_serialize_object_type(object_type).c_str()); } if (status != SAI_STATUS_SUCCESS) { SWSS_LOG_THROW("failed to execute bulk api, FIXME"); } }
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); } }
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 channelOpSetStats( _In_ const std::string &key, _In_ const std::vector<swss::FieldValueTuple> &values) { SWSS_LOG_ENTER(); // NOTE: we need to find stats for specific object, later SAI already have // this feature and this search could be optimized here: // https://github.com/opencomputeproject/SAI/commit/acc83933ff21c68e8ef10c9826de45807fdc0438 sai_object_id_t oid; sai_deserialize_object_id(key, oid); sai_object_type_t ot = sai_object_type_query(oid); if (ot == SAI_OBJECT_TYPE_NULL) { SWSS_LOG_ERROR("invalid object id: %s", key.c_str()); return; } sai_object_id_t switch_id = sai_switch_id_query(oid); if (switch_id == SAI_NULL_OBJECT_ID) { SWSS_LOG_ERROR("unable to get switch_id from oid: %s", key.c_str()); return; } /* * Check if object for statistics was created and exists on switch. */ auto &objectHash = g_switch_state_map.at(switch_id)->objectHash.at(ot); auto it = objectHash.find(key.c_str()); if (it == objectHash.end()) { SWSS_LOG_ERROR("object not found: %s", key.c_str()); return; } /* * Check if object for statistics have statistic map created, if not * create empty map. */ auto &countersMap = g_switch_state_map.at(switch_id)->countersMap; auto mapit = countersMap.find(key); if (mapit == countersMap.end()) countersMap[key] = std::map<int,uint64_t>(); /* * Find stats enum based on object type. In new metadata we have enum on * object type, but here we need to find it manually enum is in format * "sai_" + object_type + "_stat_t" */ std::string lower_ot = sai_serialize_object_type(ot).substr(16); // 16 = skip "SAI_OBJECT_TYPE_" std::transform(lower_ot.begin(), lower_ot.end(), lower_ot.begin(), ::tolower); std::string stat_enum_name = "sai_" + lower_ot + "_stat_t"; const sai_enum_metadata_t* statenum = NULL; for (size_t i = 0; i < sai_metadata_all_enums_count; ++i) { if (sai_metadata_all_enums[i]->name == stat_enum_name) { SWSS_LOG_INFO("found enum %s", stat_enum_name.c_str()); // found statenum = sai_metadata_all_enums[i]; break; } } if (statenum == NULL) { SWSS_LOG_ERROR("failed to find stat enum: %s", stat_enum_name.c_str()); return; } for (auto v: values) { // value format: stat_enum_name:uint64 auto name = fvField(v); uint64_t value; if (sscanf(fvValue(v).c_str(), "%lu", &value) != 1) { SWSS_LOG_ERROR("failed to deserialize %s as couner value uint64_t", fvValue(v).c_str()); } // linear search int enumvalue = -1; for (size_t i = 0; i < statenum->valuescount; ++i) { if (statenum->valuesnames[i] == name) { enumvalue = statenum->values[i]; break; } } if (enumvalue == -1) { SWSS_LOG_ERROR("failed to find enum value: %s", name.c_str()); continue; } SWSS_LOG_DEBUG("writting %s = %lu on %s", name.c_str(), value, key.c_str()); countersMap.at(key)[enumvalue] = value; } }
sai_status_t handle_generic( _In_ sai_object_type_t object_type, _In_ 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(); int index = 0; sai_object_id_t object_id; sai_deserialize_primitive(str_object_id, index, object_id); SWSS_LOG_DEBUG("common generic api: %d", api); switch(api) { case SAI_COMMON_API_CREATE: { SWSS_LOG_DEBUG("generic create for object type %x", object_type); create_fn create = common_create[object_type]; if (create == NULL) { SWSS_LOG_ERROR("create function is not defined for object type %x", object_type); exit(EXIT_FAILURE); } sai_object_id_t real_object_id; sai_status_t status = create(&real_object_id, attr_count, attr_list); if (status == SAI_STATUS_SUCCESS) { // object was created so new object id was generated // we need to save virtual id's to redis db std::string str_vid; std::string str_rid; sai_serialize_primitive(object_id, str_vid); sai_serialize_primitive(real_object_id, str_rid); g_redisClient->hset(VIDTORID, str_vid, str_rid); g_redisClient->hset(RIDTOVID, str_rid, str_vid); SWSS_LOG_INFO("saved VID %s to RID %s", str_vid.c_str(), str_rid.c_str()); } else { SWSS_LOG_ERROR("failed to create %d", status); } return status; } case SAI_COMMON_API_REMOVE: { SWSS_LOG_DEBUG("generic remove for object type %x", object_type); remove_fn remove = common_remove[object_type]; if (remove == NULL) { SWSS_LOG_ERROR("remove function is not defined for object type %x", object_type); exit(EXIT_FAILURE); } sai_object_id_t rid = translate_vid_to_rid(object_id); std::string str_vid; sai_serialize_primitive(object_id, str_vid); std::string str_rid; sai_serialize_primitive(rid, str_rid); g_redisClient->hdel(VIDTORID, str_vid); g_redisClient->hdel(RIDTOVID, str_rid); return remove(rid); } case SAI_COMMON_API_SET: { SWSS_LOG_DEBUG("generic set for object type %x", object_type); set_attribute_fn set = common_set_attribute[object_type]; if (set == NULL) { SWSS_LOG_ERROR("set function is not defined for object type %x", object_type); exit(EXIT_FAILURE); } sai_object_id_t rid = translate_vid_to_rid(object_id); return set(rid, attr_list); } case SAI_COMMON_API_GET: { SWSS_LOG_DEBUG("generic get for object type %x", object_type); get_attribute_fn get = common_get_attribute[object_type]; if (get == NULL) { SWSS_LOG_ERROR("get function is not defined for object type %x", object_type); exit(EXIT_FAILURE); } sai_object_id_t rid = translate_vid_to_rid(object_id); return get(rid, attr_count, attr_list); } default: SWSS_LOG_ERROR("generic other apis not implemented"); exit(EXIT_FAILURE); } }
sai_status_t internal_redis_generic_get_stats( _In_ sai_object_type_t object_type, _In_ const std::string &serialized_object_id, _In_ const sai_enum_metadata_t *stats_enum, _In_ uint32_t count, _In_ const int32_t *counter_id_list, _Out_ uint64_t *counter_list) { SWSS_LOG_ENTER(); std::vector<swss::FieldValueTuple> entry = serialize_counter_id_list( stats_enum, count, counter_id_list); std::string str_object_type = sai_serialize_object_type(object_type); std::string key = str_object_type + ":" + serialized_object_id; SWSS_LOG_DEBUG("generic get stats key: %s, fields: %lu", key.c_str(), entry.size()); if (g_record) { recordLine("m|" + key + "|" + joinFieldValues(entry)); } // get is special, it will not put data // into asic view, only to message queue g_asicState->set(key, entry, "get_stats"); // wait for response swss::Select s; s.addSelectable(g_redisGetConsumer.get()); while (true) { SWSS_LOG_DEBUG("wait for get_stats response"); swss::Selectable *sel; int result = s.select(&sel, GET_RESPONSE_TIMEOUT); if (result == swss::Select::OBJECT) { swss::KeyOpFieldsValuesTuple kco; g_redisGetConsumer->pop(kco); const std::string &op = kfvOp(kco); const std::string &opkey = kfvKey(kco); SWSS_LOG_DEBUG("response: op = %s, key = %s", opkey.c_str(), op.c_str()); if (op != "getresponse") // ignore non response messages { continue; } sai_status_t status = internal_redis_get_stats_process( object_type, count, counter_list, kco); if (g_record) { const auto &str_status = kfvKey(kco); const auto &values = kfvFieldsValues(kco); // first serialized is status recordLine("M|" + str_status + "|" + joinFieldValues(values)); } SWSS_LOG_DEBUG("generic get status: %d", status); return status; } SWSS_LOG_ERROR("generic get failed due to SELECT operation result"); break; } if (g_record) { recordLine("M|SAI_STATUS_FAILURE"); } SWSS_LOG_ERROR("generic get stats failed to get response"); return SAI_STATUS_FAILURE; }