diff --git a/lib/inc/sairedis.h b/lib/inc/sairedis.h index 610e3952e5f7..369fe0121a0e 100644 --- a/lib/inc/sairedis.h +++ b/lib/inc/sairedis.h @@ -11,6 +11,9 @@ extern "C" { #define ASIC_STATE_TABLE "ASIC_STATE" #define TEMP_PREFIX "TEMP_" +const std::string attrEnumValuesCapabilityQuery("attr_enum_values_capability_query"); +const std::string attrEnumValuesCapabilityResponse("attr_enum_values_capability_response"); + typedef enum _sai_redis_notify_syncd_t { SAI_REDIS_NOTIFY_SYNCD_INIT_VIEW, diff --git a/lib/src/sai_redis_interfacequery.cpp b/lib/src/sai_redis_interfacequery.cpp index ac4ab5bf3b72..1647ac0f18b8 100644 --- a/lib/src/sai_redis_interfacequery.cpp +++ b/lib/src/sai_redis_interfacequery.cpp @@ -1,6 +1,8 @@ #include "sai_redis.h" #include "sairedis.h" +#include "meta/sai_serialize.h" + #include "swss/selectableevent.h" #include @@ -258,3 +260,153 @@ sai_status_t sai_api_query( return SAI_STATUS_INVALID_PARAMETER; } } + +sai_status_t sai_query_attribute_enum_values_capability( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _In_ sai_attr_id_t attr_id, + _Inout_ sai_s32_list_t *enum_values_capability) +{ + MUTEX(); + + SWSS_LOG_ENTER(); + + const std::string switch_id_str = sai_serialize_object_id(switch_id); + const std::string object_type_str = sai_serialize_object_type(object_type); + + auto meta = sai_metadata_get_attr_metadata(object_type, attr_id); + if (meta == NULL) + { + SWSS_LOG_ERROR("Failed to find attribute metadata: object type %s, attr id %d", object_type_str.c_str(), attr_id); + return SAI_STATUS_INVALID_PARAMETER; + } + + const std::string attr_id_str = sai_serialize_attr_id(*meta); + const std::string list_size = std::to_string(enum_values_capability->count); + + const std::vector query_arguments = + { + swss::FieldValueTuple("OBJECT_TYPE", object_type_str), + swss::FieldValueTuple("ATTR_ID", attr_id_str), + swss::FieldValueTuple("LIST_SIZE", list_size) + }; + + SWSS_LOG_DEBUG( + "Query arguments: switch %s, object type: %s, attribute: %s, count: %s", + switch_id_str.c_str(), + object_type_str.c_str(), + attr_id_str.c_str(), + list_size.c_str() + ); + + if (g_record) + { + recordLine("q|attribute_enum_values_capability|" + switch_id_str + "|" + joinFieldValues(query_arguments)); + } + + // This query will not put any data into the ASIC view, just into the + // message queue + g_asicState->set(switch_id_str, query_arguments, attrEnumValuesCapabilityQuery); + + swss::Select callback; + callback.addSelectable(g_redisGetConsumer.get()); + + while (true) + { + SWSS_LOG_DEBUG("Waiting for a response"); + + swss::Selectable *sel; + + auto result = callback.select(&sel, GET_RESPONSE_TIMEOUT); + + if (result == swss::Select::OBJECT) + { + swss::KeyOpFieldsValuesTuple kco; + + g_redisGetConsumer->pop(kco); + + const std::string &message_type = kfvOp(kco); + const std::string &status_str = kfvKey(kco); + + SWSS_LOG_DEBUG("Received response: op = %s, key = %s", message_type.c_str(), status_str.c_str()); + + // Ignore messages that are not in response to our query + if (message_type != attrEnumValuesCapabilityResponse) + { + continue; + } + + sai_status_t status; + sai_deserialize_status(status_str, status); + + if (status == SAI_STATUS_SUCCESS) + { + const std::vector &values = kfvFieldsValues(kco); + + if (values.size() != 2) + { + if (g_record) + { + recordLine("Q|attribute_enum_values_capability|SAI_STATUS_FAILURE"); + } + + SWSS_LOG_ERROR("Invalid response from syncd: expected 2 values, received %d", values.size()); + return SAI_STATUS_FAILURE; + } + + const std::string &capability_str = fvValue(values[0]); + const uint32_t num_capabilities = std::stoi(fvValue(values[1])); + + SWSS_LOG_DEBUG("Received payload: capabilites = '%s', count = %d", capability_str.c_str(), num_capabilities); + + enum_values_capability->count = num_capabilities; + + size_t position = 0; + for (uint32_t i = 0; i < num_capabilities; i++) + { + size_t old_position = position; + position = capability_str.find(",", old_position); + std::string capability = capability_str.substr(old_position, position - old_position); + enum_values_capability->list[i] = std::stoi(capability); + + // We have run out of values to add to our list + if (position == std::string::npos) + { + if (num_capabilities != i + 1) + { + SWSS_LOG_WARN("Query returned less attributes than expected: expected %d, recieved %d"); + } + + break; + } + + // Skip the commas + position++; + } + + if (g_record) + { + recordLine("Q|attribute_enum_values_capability|" + status_str + "|" + joinFieldValues(values)); + } + } + else + { + if (g_record) + { + recordLine("Q|attribute_enum_values_capability|" + status_str); + } + } + + SWSS_LOG_DEBUG("Status: %s", status_str.c_str()); + return status; + } + } + + if (g_record) + { + recordLine("Q|attribute_enum_values_capability|SAI_STATUS_FAILURE"); + } + + SWSS_LOG_ERROR("Failed to receive a response from syncd"); + return SAI_STATUS_FAILURE; +} diff --git a/saiplayer/saiplayer.cpp b/saiplayer/saiplayer.cpp index edf8c441676e..267ce8831446 100644 --- a/saiplayer/saiplayer.cpp +++ b/saiplayer/saiplayer.cpp @@ -1210,6 +1210,11 @@ int replay(int argc, char **argv) case 'g': api = SAI_COMMON_API_GET; break; + case 'q': + // TODO: implement SAI player support for query commands + continue; + case 'Q': + continue; // skip over query responses case '#': case 'n': continue; // skip comment and notification diff --git a/syncd/syncd.cpp b/syncd/syncd.cpp index f1065e0383ae..752e113ee84f 100644 --- a/syncd/syncd.cpp +++ b/syncd/syncd.cpp @@ -2867,6 +2867,72 @@ sai_status_t processFdbFlush( return status; } +sai_status_t processAttrEnumValuesCapabilityQuery( + _In_ const swss::KeyOpFieldsValuesTuple &kco) +{ + SWSS_LOG_ENTER(); + + const std::string &switch_str_id = kfvKey(kco); + + sai_object_id_t switch_vid; + sai_deserialize_object_id(switch_str_id, switch_vid); + + const sai_object_id_t switch_rid = translate_vid_to_rid(switch_vid); + + const std::vector &values = kfvFieldsValues(kco); + + if (values.size() != 3) + { + SWSS_LOG_ERROR("Invalid input: expected 3 arguments, received %d", values.size()); + getResponse->set(sai_serialize_status(SAI_STATUS_INVALID_PARAMETER), {}, attrEnumValuesCapabilityResponse); + return SAI_STATUS_INVALID_PARAMETER; + } + + sai_object_type_t object_type; + sai_deserialize_object_type(fvValue(values[0]), object_type); + + sai_attr_id_t attr_id; + sai_deserialize_attr_id(fvValue(values[1]), attr_id); + + const uint32_t list_size = std::stoi(fvValue(values[2])); + std::vector enum_capabilities_list(list_size); + + sai_s32_list_t enum_values_capability; + enum_values_capability.count = list_size; + enum_values_capability.list = enum_capabilities_list.data(); + + sai_status_t status = sai_query_attribute_enum_values_capability(switch_rid, object_type, attr_id, &enum_values_capability); + + std::vector response_payload; + + if (status == SAI_STATUS_SUCCESS) + { + std::string serialized_enum_capabilities; + for (uint32_t i = 0; i < enum_values_capability.count; i++) + { + // We will remove the leading comma before sending the response + serialized_enum_capabilities += ','; + serialized_enum_capabilities += std::to_string(enum_capabilities_list[i]); + } + + if (!serialized_enum_capabilities.empty()) + { + serialized_enum_capabilities = serialized_enum_capabilities.substr(1); + } + + response_payload = + { + swss::FieldValueTuple("ENUM_CAPABILITIES", serialized_enum_capabilities), + swss::FieldValueTuple("ENUM_COUNT", std::to_string(enum_values_capability.count)) + }; + + SWSS_LOG_DEBUG("Sending response: capabilities = '%s', count = %d", serialized_enum_capabilities.substr(1).c_str(), enum_values_capability.count); + } + + getResponse->set(sai_serialize_status(status), response_payload, attrEnumValuesCapabilityResponse); + return status; +} + sai_status_t processEvent( _In_ swss::ConsumerTable &consumer) { @@ -2959,6 +3025,10 @@ sai_status_t processEvent( { return processFdbFlush(kco); } + else if (op == attrEnumValuesCapabilityQuery) + { + return processAttrEnumValuesCapabilityQuery(kco); + } else { SWSS_LOG_THROW("api '%s' is not implemented", op.c_str()); diff --git a/tests/brcm.pl b/tests/brcm.pl index 9e140ccf1595..12de57e3d467 100755 --- a/tests/brcm.pl +++ b/tests/brcm.pl @@ -518,6 +518,13 @@ sub test_brcm_warm_boot_port_create request_warm_shutdown; } +sub test_brcm_query_attr_enum_values_capability +{ + fresh_start; + + play "query_attr_enum_values_capability.rec"; +} + # RUN TESTS test_brcm_warm_boot_port_remove; @@ -568,5 +575,6 @@ sub test_brcm_warm_boot_port_create test_brcm_full_to_empty_no_queue_no_ipg; test_brcm_full_to_empty_hostif_remove_segfault; test_brcm_full_to_empty_no_queue_no_ipg_no_buffer_profile; +test_brcm_query_attr_enum_values_capability; kill_syncd; diff --git a/tests/brcm/query_attr_enum_values_capability.rec b/tests/brcm/query_attr_enum_values_capability.rec new file mode 100644 index 000000000000..e5b020dce845 --- /dev/null +++ b/tests/brcm/query_attr_enum_values_capability.rec @@ -0,0 +1,9 @@ +2019-10-25.04:21:31.884173|a|INIT_VIEW +2019-10-25.04:21:31.884636|A|SAI_STATUS_SUCCESS +2019-10-25.04:21:31.884882|c|SAI_OBJECT_TYPE_SWITCH:oid:0x21000000000000|SAI_SWITCH_ATTR_INIT_SWITCH=true|SAI_SWITCH_ATTR_SRC_MAC_ADDRESS=02:42:AC:11:00:02 +2019-10-25.04:21:32.853334|q|attribute_enum_values_capability|oid:0x21000000000000|OBJECT_TYPE=SAI_OBJECT_TYPE_DEBUG_COUNTER|ATTR_ID=SAI_DEBUG_COUNTER_ATTR_IN_DROP_REASON_LIST|LIST_SIZE=100 +2019-10-25.04:21:32.854651|Q|attribute_enum_values_capability|SAI_STATUS_SUCCESS|ENUM_CAPABILITIES=0,11,41|ENUM_COUNT=3 +2019-10-25.04:21:32.854730|q|attribute_enum_values_capability|oid:0x21000000000000|OBJECT_TYPE=SAI_OBJECT_TYPE_DEBUG_COUNTER|ATTR_ID=SAI_DEBUG_COUNTER_ATTR_OUT_DROP_REASON_LIST|LIST_SIZE=100 +2019-10-25.04:21:32.855398|Q|attribute_enum_values_capability|SAI_STATUS_SUCCESS|ENUM_CAPABILITIES=0,2|ENUM_COUNT=2 +2019-10-25.04:21:32.862373|a|APPLY_VIEW +2019-10-25.04:21:32.863487|A|SAI_STATUS_SUCCESS diff --git a/vslib/src/sai_vs_interfacequery.cpp b/vslib/src/sai_vs_interfacequery.cpp index 60605055e7b7..2d1a0c30c339 100644 --- a/vslib/src/sai_vs_interfacequery.cpp +++ b/vslib/src/sai_vs_interfacequery.cpp @@ -921,3 +921,45 @@ sai_status_t sai_api_query( return SAI_STATUS_INVALID_PARAMETER; } } + +sai_status_t sai_query_attribute_enum_values_capability( + _In_ sai_object_id_t switch_id, + _In_ sai_object_type_t object_type, + _In_ sai_attr_id_t attr_id, + _Inout_ sai_s32_list_t *enum_values_capability) +{ + SWSS_LOG_ENTER(); + + // TODO: We should generate this metadata for the virtual switch rather than hard-coding it here. + if (object_type == SAI_OBJECT_TYPE_DEBUG_COUNTER && attr_id == SAI_DEBUG_COUNTER_ATTR_IN_DROP_REASON_LIST) + { + if (enum_values_capability->count < 3) + { + return SAI_STATUS_BUFFER_OVERFLOW; + } + + enum_values_capability->count = 3; + enum_values_capability->list[0] = SAI_IN_DROP_REASON_L2_ANY; + enum_values_capability->list[1] = SAI_IN_DROP_REASON_L3_ANY; + enum_values_capability->list[2] = SAI_IN_DROP_REASON_ACL_ANY; + + return SAI_STATUS_SUCCESS; + } + else if (object_type == SAI_OBJECT_TYPE_DEBUG_COUNTER && attr_id == SAI_DEBUG_COUNTER_ATTR_OUT_DROP_REASON_LIST) + { + if (enum_values_capability->count < 2) + { + return SAI_STATUS_BUFFER_OVERFLOW; + } + + enum_values_capability->count = 2; + enum_values_capability->list[0] = SAI_OUT_DROP_REASON_L2_ANY; + enum_values_capability->list[1] = SAI_OUT_DROP_REASON_L3_ANY; + + return SAI_STATUS_SUCCESS; + } + else + { + return SAI_STATUS_NOT_SUPPORTED; + } +}