meta/sai_rpc_frontend.cpp (890 lines of code) (raw):

/** * Copyright (c) 2021 Microsoft Open Technologies, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. You may obtain * a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT * LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS * FOR A PARTICULAR PURPOSE, MERCHANTABILITY OR NON-INFRINGEMENT. * * See the Apache Version 2.0 License for specific language governing * permissions and limitations under the License. * * Microsoft would like to thank the following companies for their review and * assistance with these files: Intel Corporation, Mellanox Technologies Ltd, * Dell Products, L.P., Facebook, Inc., Marvell International Ltd. * * @file sai_rpc_frontend.cpp * * @brief This module contains RPC server handler and helper functions */ #include <arpa/inet.h> #include "sai_rpc.h" extern "C" { #include "saimetadata.h" } #include <iostream> #include <cstring> using namespace ::sai; /** * @brief Convert Thrift MAC format to SAI MAC format */ static unsigned int sai_thrift_mac_t_parse(const std::string s, void *data) { unsigned int i, j = 0; unsigned char *m = static_cast<unsigned char *>(data); memset(m, 0, 6); for (i = 0; i < s.size(); i++) { char let = s.c_str()[i]; if (let >= '0' && let <= '9') { m[j / 2] = (unsigned char)((m[j / 2] << 4) + (let - '0')); j++; } else if (let >= 'a' && let <= 'f') { m[j / 2] = (unsigned char)((m[j / 2] << 4) + (let - 'a' + 10)); j++; } else if (let >= 'A' && let <= 'F') { m[j / 2] = (unsigned char)((m[j / 2] << 4) + (let - 'A' + 10)); j++; } } return (j == 12); } /** * @brief Convert Thrift IPv4 format to SAI IPv4 format */ static void sai_thrift_ip4_t_parse(const std::string s, unsigned int *m) { unsigned char r = 0; unsigned int i; *m = 0; for (i = 0; i < s.size(); i++) { char let = s.c_str()[i]; if (let >= '0' && let <= '9') { r = (unsigned char)((r * 10) + (let - '0')); } else { *m = (*m << 8) | r; r = 0; } } *m = (*m << 8) | (r & 0xFF); *m = htonl(*m); } /** * @brief Convert Thrift IPv6 format to SAI IPv6 format */ static void sai_thrift_ip6_t_parse(const std::string s, unsigned char *v6_ip) { const char *v6_str = s.c_str(); inet_pton(AF_INET6, v6_str, v6_ip); } /** * @brief Convert Thrift IP address format to SAI IP address format */ static void sai_thrift_ip_address_t_parse( const sai_thrift_ip_address_t &thrift_ip_address, sai_ip_address_t *ip_address) { ip_address->addr_family = (sai_ip_addr_family_t)thrift_ip_address.addr_family; if ((sai_ip_addr_family_t)thrift_ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { sai_thrift_ip4_t_parse(thrift_ip_address.addr.ip4, &ip_address->addr.ip4); } else { sai_thrift_ip6_t_parse(thrift_ip_address.addr.ip6, ip_address->addr.ip6); } } /** * @brief Convert IP address and mask from Thrift to SAI format */ static void sai_thrift_ip_prefix_t_parse( const sai_thrift_ip_prefix_t &thrift_ip_prefix, sai_ip_prefix_t *ip_prefix) { ip_prefix->addr_family = (sai_ip_addr_family_t)thrift_ip_prefix.addr_family; if ((sai_ip_addr_family_t)thrift_ip_prefix.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { sai_thrift_ip4_t_parse(thrift_ip_prefix.addr.ip4, &ip_prefix->addr.ip4); sai_thrift_ip4_t_parse(thrift_ip_prefix.mask.ip4, &ip_prefix->mask.ip4); } else { sai_thrift_ip6_t_parse(thrift_ip_prefix.addr.ip6, ip_prefix->addr.ip6); sai_thrift_ip6_t_parse(thrift_ip_prefix.mask.ip6, ip_prefix->mask.ip6); } } /** * @brief Convert attribute from Thrift to SAI format according to the type */ void convert_attr_thrift_to_sai( const sai_object_type_t ot, const sai_thrift_attribute_t &thrift_attr, sai_attribute_t *attr) { const auto md = sai_metadata_get_attr_metadata(ot, thrift_attr.id); attr->id = thrift_attr.id; sai_thrift_exception e; e.status = SAI_STATUS_NOT_SUPPORTED; if (md == NULL) { SAI_META_LOG_ERROR("attr metadata not found for object type %d and attribute %d", ot, attr->id); e.status = SAI_STATUS_INVALID_PARAMETER; throw e; } switch (md->attrvaluetype) { case SAI_ATTR_VALUE_TYPE_BOOL: attr->value.booldata = thrift_attr.value.booldata; break; case SAI_ATTR_VALUE_TYPE_CHARDATA: // 32 is chardata size in sai types std::memcpy(attr->value.chardata, thrift_attr.value.chardata.c_str(), 32); break; case SAI_ATTR_VALUE_TYPE_UINT8: attr->value.u8 = thrift_attr.value.u8; break; case SAI_ATTR_VALUE_TYPE_INT8: attr->value.s8 = thrift_attr.value.s8; break; case SAI_ATTR_VALUE_TYPE_UINT16: attr->value.u16 = thrift_attr.value.u16; break; case SAI_ATTR_VALUE_TYPE_INT16: attr->value.s16 = thrift_attr.value.s16; break; case SAI_ATTR_VALUE_TYPE_UINT32: attr->value.u32 = thrift_attr.value.u32; break; case SAI_ATTR_VALUE_TYPE_INT32: attr->value.s32 = thrift_attr.value.s32; break; case SAI_ATTR_VALUE_TYPE_UINT64: attr->value.u64 = thrift_attr.value.u64; break; case SAI_ATTR_VALUE_TYPE_INT64: attr->value.s64 = thrift_attr.value.s64; break; case SAI_ATTR_VALUE_TYPE_MAC: sai_thrift_mac_t_parse(thrift_attr.value.mac, &attr->value.mac); break; case SAI_ATTR_VALUE_TYPE_IPV4: sai_thrift_ip4_t_parse(thrift_attr.value.ip4, &attr->value.ip4); break; case SAI_ATTR_VALUE_TYPE_IPV6: sai_thrift_ip6_t_parse(thrift_attr.value.ip6, attr->value.ip6); break; case SAI_ATTR_VALUE_TYPE_IP_ADDRESS: sai_thrift_ip_address_t_parse(thrift_attr.value.ipaddr, &attr->value.ipaddr); break; case SAI_ATTR_VALUE_TYPE_IP_PREFIX: sai_thrift_ip_prefix_t_parse(thrift_attr.value.ipprefix, &attr->value.ipprefix); break; case SAI_ATTR_VALUE_TYPE_OBJECT_ID: attr->value.oid = thrift_attr.value.oid; break; case SAI_ATTR_VALUE_TYPE_OBJECT_LIST: { attr->value.objlist.list = (sai_object_id_t *)malloc(sizeof(sai_object_id_t) * thrift_attr.value.objlist.count); int i = 0; for (auto obj : thrift_attr.value.objlist.idlist) { attr->value.objlist.list[i++] = obj; } attr->value.objlist.count = thrift_attr.value.objlist.count; } break; case SAI_ATTR_VALUE_TYPE_UINT8_LIST: { attr->value.u8list.list = (uint8_t *)malloc(sizeof(uint8_t) * thrift_attr.value.u8list.count); int i = 0; for (auto u8 : thrift_attr.value.u8list.uint8list) { attr->value.u8list.list[i++] = u8; } attr->value.u8list.count = thrift_attr.value.u8list.count; } break; case SAI_ATTR_VALUE_TYPE_INT8_LIST: { attr->value.s8list.list = (int8_t *)malloc(sizeof(int8_t) * thrift_attr.value.s8list.count); int i = 0; for (auto s8 : thrift_attr.value.s8list.int8list) { attr->value.s8list.list[i++] = s8; } attr->value.s8list.count = thrift_attr.value.s8list.count; } break; case SAI_ATTR_VALUE_TYPE_UINT16_LIST: { attr->value.u16list.list = (uint16_t *)malloc(sizeof(uint16_t) * thrift_attr.value.u16list.count); int i = 0; for (auto u16 : thrift_attr.value.u16list.uint16list) { attr->value.u16list.list[i++] = u16; } attr->value.u16list.count = thrift_attr.value.u16list.count; } break; case SAI_ATTR_VALUE_TYPE_INT16_LIST: { attr->value.s16list.list = (int16_t *)malloc(sizeof(int16_t) * thrift_attr.value.s16list.count); int i = 0; for (auto s16 : thrift_attr.value.s16list.int16list) { attr->value.s16list.list[i++] = s16; } attr->value.s16list.count = thrift_attr.value.s16list.count; } break; case SAI_ATTR_VALUE_TYPE_UINT32_LIST: { attr->value.u32list.list = (uint32_t *)malloc(sizeof(uint32_t) * thrift_attr.value.u32list.count); int i = 0; for (auto u32 : thrift_attr.value.u32list.uint32list) { attr->value.u32list.list[i++] = u32; } attr->value.u32list.count = thrift_attr.value.u32list.count; } break; case SAI_ATTR_VALUE_TYPE_INT32_LIST: { attr->value.s32list.list = (int32_t *)malloc(sizeof(int32_t) * thrift_attr.value.s32list.count); int i = 0; for (auto s32 : thrift_attr.value.s32list.int32list) { attr->value.s32list.list[i++] = s32; } attr->value.s32list.count = thrift_attr.value.s32list.count; } break; case SAI_ATTR_VALUE_TYPE_UINT32_RANGE: attr->value.u32range.min = thrift_attr.value.u32range.min; attr->value.u32range.max = thrift_attr.value.u32range.max; break; case SAI_ATTR_VALUE_TYPE_INT32_RANGE: attr->value.s32range.min = thrift_attr.value.s32range.min; attr->value.s32range.max = thrift_attr.value.s32range.max; break; case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST: { attr->value.u16rangelist.list = (sai_u16_range_t *)malloc(sizeof(sai_u16_range_t) * thrift_attr.value.u16rangelist.count); int i = 0; for (auto range : thrift_attr.value.u16rangelist.rangelist) { attr->value.u16rangelist.list[i].min = range.min; attr->value.u16rangelist.list[i++].max = range.max; } attr->value.u16rangelist.count = thrift_attr.value.u16rangelist.count; } break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_BOOL: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.booldata = thrift_attr.value.aclfield.data.booldata; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.u8 = thrift_attr.value.aclfield.data.u8; attr->value.aclfield.mask.u8 = thrift_attr.value.aclfield.mask.u8; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT8: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.s8 = thrift_attr.value.aclfield.data.s8; attr->value.aclfield.mask.s8 = thrift_attr.value.aclfield.mask.s8; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT16: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.u16 = thrift_attr.value.aclfield.data.u16; attr->value.aclfield.mask.u16 = thrift_attr.value.aclfield.mask.u16; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT16: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.s16 = thrift_attr.value.aclfield.data.s16; attr->value.aclfield.mask.s16 = thrift_attr.value.aclfield.mask.s16; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT32: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.u32 = thrift_attr.value.aclfield.data.u32; attr->value.aclfield.mask.u32 = thrift_attr.value.aclfield.mask.u32; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_INT32: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.s32 = thrift_attr.value.aclfield.data.s32; attr->value.aclfield.mask.s32 = thrift_attr.value.aclfield.mask.s32; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_MAC: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; sai_thrift_mac_t_parse(thrift_attr.value.aclfield.data.mac, &attr->value.aclfield.data.mac); sai_thrift_mac_t_parse(thrift_attr.value.aclfield.mask.mac, &attr->value.aclfield.mask.mac); break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV4: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; sai_thrift_ip4_t_parse(thrift_attr.value.aclfield.data.ip4, &attr->value.aclfield.data.ip4); sai_thrift_ip4_t_parse(thrift_attr.value.aclfield.mask.ip4, &attr->value.aclfield.mask.ip4); break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_IPV6: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; sai_thrift_ip6_t_parse(thrift_attr.value.aclfield.data.ip6, attr->value.aclfield.data.ip6); sai_thrift_ip6_t_parse(thrift_attr.value.aclfield.mask.ip6, attr->value.aclfield.mask.ip6); break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID: attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.oid = thrift_attr.value.aclfield.data.oid; break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST: { int i = 0; attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.objlist.list = (sai_object_id_t *)malloc(sizeof(sai_object_id_t) * thrift_attr.value.aclfield.data.objlist.count); for (auto obj : thrift_attr.value.aclfield.data.objlist.idlist) { attr->value.aclfield.data.objlist.list[i++] = obj; } attr->value.aclfield.data.objlist.count = thrift_attr.value.aclfield.data.objlist.count; } break; case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_UINT8_LIST: { int i = 0; attr->value.aclfield.enable = thrift_attr.value.aclfield.enable; attr->value.aclfield.data.u8list.list = (uint8_t *)malloc(sizeof(uint8_t) * thrift_attr.value.aclfield.data.u8list.count); for (auto obj : thrift_attr.value.aclfield.data.u8list.uint8list) { attr->value.aclfield.data.u8list.list[i++] = obj; } attr->value.aclfield.data.u8list.count = thrift_attr.value.aclfield.data.u8list.count; i = 0; attr->value.aclfield.mask.u8list.list = (uint8_t *)malloc(sizeof(uint8_t) * thrift_attr.value.aclfield.mask.u8list.count); for (auto obj : thrift_attr.value.aclfield.mask.u8list.uint8list) { attr->value.aclfield.mask.u8list.list[i++] = obj; } attr->value.aclfield.mask.u8list.count = thrift_attr.value.aclfield.mask.u8list.count; } break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_BOOL: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.booldata = thrift_attr.value.aclaction.parameter.booldata; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT8: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.u8 = thrift_attr.value.aclaction.parameter.u8; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT8: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.s8 = thrift_attr.value.aclaction.parameter.s8; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT16: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.u16 = thrift_attr.value.aclaction.parameter.u16; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT16: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.s16 = thrift_attr.value.aclaction.parameter.s16; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_UINT32: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.u32 = thrift_attr.value.aclaction.parameter.u32; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_INT32: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.s32 = thrift_attr.value.aclaction.parameter.s32; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_MAC: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; sai_thrift_mac_t_parse(thrift_attr.value.aclaction.parameter.mac, &attr->value.aclaction.parameter.mac); break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV4: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; sai_thrift_ip4_t_parse(thrift_attr.value.aclaction.parameter.ip4, &attr->value.aclaction.parameter.ip4); break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IPV6: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; sai_thrift_ip6_t_parse(thrift_attr.value.aclaction.parameter.ip6, attr->value.aclaction.parameter.ip6); break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_IP_ADDRESS: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; sai_thrift_ip_address_t_parse(thrift_attr.value.aclaction.parameter.ipaddr, &attr->value.aclaction.parameter.ipaddr); break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID: attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.oid = thrift_attr.value.aclaction.parameter.oid; break; case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST: { int i = 0; attr->value.aclaction.enable = thrift_attr.value.aclaction.enable; attr->value.aclaction.parameter.objlist.list = (sai_object_id_t*)malloc(sizeof(sai_object_id_t) * thrift_attr.value.aclaction.parameter.objlist.count); for (auto obj : thrift_attr.value.aclaction.parameter.objlist.idlist) { attr->value.aclaction.parameter.objlist.list[i++] = obj; } attr->value.aclaction.parameter.objlist.count = thrift_attr.value.aclaction.parameter.objlist.count; } break; case SAI_ATTR_VALUE_TYPE_ACL_CAPABILITY: { attr->value.aclcapability.is_action_list_mandatory = thrift_attr.value.aclcapability.is_action_list_mandatory; attr->value.aclcapability.action_list.list = (int32_t *)malloc(sizeof(int32_t) * thrift_attr.value.aclcapability.action_list.count); int i = 0; for (auto s32 : thrift_attr.value.aclcapability.action_list.int32list) { attr->value.aclcapability.action_list.list[i++] = s32; } attr->value.aclcapability.action_list.count = thrift_attr.value.aclcapability.action_list.count; } break; case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST: { attr->value.aclresource.list = (sai_acl_resource_t *)malloc(sizeof(sai_acl_resource_t) * thrift_attr.value.aclresource.count); int i = 0; for (auto resource : thrift_attr.value.aclresource.resourcelist) { attr->value.aclresource.list[i].stage = static_cast<sai_acl_stage_t>(resource.stage); attr->value.aclresource.list[i].bind_point = static_cast<sai_acl_bind_point_type_t>(resource.bind_point); attr->value.aclresource.list[i++].avail_num = resource.avail_num; } attr->value.aclresource.count = thrift_attr.value.aclresource.count; } break; case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST: { attr->value.ipaddrlist.list = (sai_ip_address_t *)malloc(sizeof(sai_ip_address_t) * thrift_attr.value.ipaddrlist.count); int i = 0; for (auto address : thrift_attr.value.ipaddrlist.addresslist) { sai_thrift_ip_address_t_parse(address, &attr->value.ipaddrlist.list[i++]); } attr->value.ipaddrlist.count = thrift_attr.value.ipaddrlist.count; } break; case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST: { attr->value.ipprefixlist.list = (sai_ip_prefix_t *)malloc(sizeof(sai_ip_prefix_t) * thrift_attr.value.ipprefixlist.count); int i = 0; for (auto address : thrift_attr.value.ipprefixlist.prefixlist) { sai_thrift_ip_prefix_t_parse(address, &attr->value.ipprefixlist.list[i++]); } attr->value.ipprefixlist.count = thrift_attr.value.ipprefixlist.count; } break; case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST: { attr->value.qosmap.list = (sai_qos_map_t *)malloc(sizeof(sai_qos_map_t) * thrift_attr.value.qosmap.count); int i = 0; for (auto qosmap : thrift_attr.value.qosmap.maplist) { // key attr->value.qosmap.list[i].key.tc = qosmap.key.tc; attr->value.qosmap.list[i].key.dscp = qosmap.key.dscp; attr->value.qosmap.list[i].key.dot1p = qosmap.key.dot1p; attr->value.qosmap.list[i].key.prio = qosmap.key.prio; attr->value.qosmap.list[i].key.pg = qosmap.key.pg; attr->value.qosmap.list[i].key.queue_index = qosmap.key.queue_index; attr->value.qosmap.list[i].key.color = static_cast<sai_packet_color_t>(qosmap.key.color); attr->value.qosmap.list[i].key.mpls_exp = qosmap.key.mpls_exp; // value attr->value.qosmap.list[i].value.tc = qosmap.value.tc; attr->value.qosmap.list[i].value.dscp = qosmap.value.dscp; attr->value.qosmap.list[i].value.dot1p = qosmap.value.dot1p; attr->value.qosmap.list[i].value.prio = qosmap.value.prio; attr->value.qosmap.list[i].value.pg = qosmap.value.pg; attr->value.qosmap.list[i].value.queue_index = qosmap.value.queue_index; attr->value.qosmap.list[i].value.color = static_cast<sai_packet_color_t>(qosmap.value.color); attr->value.qosmap.list[i].value.mpls_exp = qosmap.value.mpls_exp; i++; } attr->value.qosmap.count = thrift_attr.value.qosmap.count; } break; default: SAI_META_LOG_ERROR("attr value type not supported for %s", md->attridname); throw e; } } /** * @brief Convert SAI IPv4 format to Thrift IPv4 format */ static std::string sai_ip4_t_to_thrift(const sai_ip4_t ip4) { char str[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(ip4), str, INET_ADDRSTRLEN); return str; } /** * @brief Convert SAI IPv6 format to Thrift IPv6 format */ static std::string sai_ip6_t_to_thrift(const sai_ip6_t ip6) { char str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, ip6, str, INET6_ADDRSTRLEN); return str; } /** * @brief Convert SAI IP address format to Thrift IP address format */ static void sai_ip_address_t_to_thrift(sai_thrift_ip_address_t &thrift_ip, const sai_ip_address_t ip) { if (ip.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { thrift_ip.addr_family = SAI_IP_ADDR_FAMILY_IPV4; thrift_ip.addr.ip4 = sai_ip4_t_to_thrift(ip.addr.ip4); } else if (ip.addr_family == SAI_IP_ADDR_FAMILY_IPV6) { thrift_ip.addr_family = SAI_IP_ADDR_FAMILY_IPV6; thrift_ip.addr.ip6 = sai_ip6_t_to_thrift(ip.addr.ip6); } } /** * @brief Convert IP address and mask from SAI to Thrift format */ static void sai_ip_prefix_t_to_thrift(sai_thrift_ip_prefix_t &thrift_ip, const sai_ip_prefix_t ip) { if (ip.addr_family == SAI_IP_ADDR_FAMILY_IPV4) { thrift_ip.addr_family = SAI_IP_ADDR_FAMILY_IPV4; thrift_ip.addr.ip4 = sai_ip4_t_to_thrift(ip.addr.ip4); thrift_ip.mask.ip4 = sai_ip4_t_to_thrift(ip.mask.ip4); } else if (ip.addr_family == SAI_IP_ADDR_FAMILY_IPV6) { thrift_ip.addr_family = SAI_IP_ADDR_FAMILY_IPV6; thrift_ip.addr.ip6 = sai_ip6_t_to_thrift(ip.addr.ip6); thrift_ip.mask.ip6 = sai_ip6_t_to_thrift(ip.mask.ip6); } } /** * @brief Convert attribute from SAI to Thrift format according to the type */ void convert_attr_sai_to_thrift( const sai_object_type_t ot, const sai_attribute_t &attr, sai_thrift_attribute_t &thrift_attr) { const auto md = sai_metadata_get_attr_metadata(ot, attr.id); thrift_attr.id = attr.id; sai_thrift_exception e; e.status = SAI_STATUS_NOT_SUPPORTED; if (md == NULL) { SAI_META_LOG_ERROR("attr metadata not found for object type %d and attribute %d", ot, attr.id); e.status = SAI_STATUS_INVALID_PARAMETER; throw e; } switch (md->attrvaluetype) { case SAI_ATTR_VALUE_TYPE_BOOL: thrift_attr.value.booldata = attr.value.booldata; break; case SAI_ATTR_VALUE_TYPE_CHARDATA: thrift_attr.value.chardata = attr.value.chardata; break; case SAI_ATTR_VALUE_TYPE_UINT8: thrift_attr.value.u8 = attr.value.u8; break; case SAI_ATTR_VALUE_TYPE_INT8: thrift_attr.value.s8 = attr.value.s8; break; case SAI_ATTR_VALUE_TYPE_UINT16: thrift_attr.value.u16 = attr.value.u16; break; case SAI_ATTR_VALUE_TYPE_INT16: thrift_attr.value.s16 = attr.value.s16; break; case SAI_ATTR_VALUE_TYPE_UINT32: thrift_attr.value.u32 = attr.value.u32; break; case SAI_ATTR_VALUE_TYPE_INT32: thrift_attr.value.s32 = attr.value.s32; break; case SAI_ATTR_VALUE_TYPE_UINT64: thrift_attr.value.u64 = attr.value.u64; break; case SAI_ATTR_VALUE_TYPE_INT64: thrift_attr.value.s64 = attr.value.s64; break; case SAI_ATTR_VALUE_TYPE_MAC: { char mac_str[18]; snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", attr.value.mac[0], attr.value.mac[1], attr.value.mac[2], attr.value.mac[3], attr.value.mac[4], attr.value.mac[5]); thrift_attr.value.mac = mac_str; } break; case SAI_ATTR_VALUE_TYPE_IPV4: thrift_attr.value.ip4 = sai_ip4_t_to_thrift(attr.value.ip4); break; case SAI_ATTR_VALUE_TYPE_IPV6: thrift_attr.value.ip6 = sai_ip6_t_to_thrift(attr.value.ip6); break; case SAI_ATTR_VALUE_TYPE_IP_ADDRESS: sai_ip_address_t_to_thrift(thrift_attr.value.ipaddr, attr.value.ipaddr); break; case SAI_ATTR_VALUE_TYPE_IP_PREFIX: sai_ip_prefix_t_to_thrift(thrift_attr.value.ipprefix, attr.value.ipprefix); break; case SAI_ATTR_VALUE_TYPE_OBJECT_ID: thrift_attr.value.oid = attr.value.oid; break; case SAI_ATTR_VALUE_TYPE_OBJECT_LIST: { for (unsigned int i = 0; i < attr.value.objlist.count; i++) { thrift_attr.value.objlist.idlist.push_back(attr.value.objlist.list[i]); } thrift_attr.value.objlist.count = attr.value.objlist.count; free(attr.value.objlist.list); } break; case SAI_ATTR_VALUE_TYPE_UINT8_LIST: { for (unsigned int i = 0; i < attr.value.u8list.count; i++) { thrift_attr.value.u8list.uint8list.push_back(attr.value.u8list.list[i]); } thrift_attr.value.u8list.count = attr.value.u8list.count; free(attr.value.u8list.list); } break; case SAI_ATTR_VALUE_TYPE_INT8_LIST: { for (unsigned int i = 0; i < attr.value.s8list.count; i++) { thrift_attr.value.s8list.int8list.push_back(attr.value.s8list.list[i]); } thrift_attr.value.s8list.count = attr.value.s8list.count; free(attr.value.s8list.list); } break; case SAI_ATTR_VALUE_TYPE_UINT16_LIST: { for (unsigned int i = 0; i < attr.value.u16list.count; i++) { thrift_attr.value.u16list.uint16list.push_back(attr.value.u16list.list[i]); } thrift_attr.value.u16list.count = attr.value.u16list.count; free(attr.value.u16list.list); } break; case SAI_ATTR_VALUE_TYPE_INT16_LIST: { for (unsigned int i = 0; i < attr.value.s16list.count; i++) { thrift_attr.value.s16list.int16list.push_back(attr.value.s16list.list[i]); } thrift_attr.value.s16list.count = attr.value.s16list.count; free(attr.value.s16list.list); } break; case SAI_ATTR_VALUE_TYPE_UINT32_LIST: { for (unsigned int i = 0; i < attr.value.u32list.count; i++) { thrift_attr.value.u32list.uint32list.push_back(attr.value.u32list.list[i]); } thrift_attr.value.u32list.count = attr.value.u32list.count; free(attr.value.u32list.list); } break; case SAI_ATTR_VALUE_TYPE_INT32_LIST: { for (unsigned int i = 0; i < attr.value.s32list.count; i++) { thrift_attr.value.s32list.int32list.push_back(attr.value.s32list.list[i]); } thrift_attr.value.s32list.count = attr.value.s32list.count; free(attr.value.s32list.list); } break; case SAI_ATTR_VALUE_TYPE_UINT32_RANGE: thrift_attr.value.u32range.min = attr.value.u32range.min; thrift_attr.value.u32range.max = attr.value.u32range.max; break; case SAI_ATTR_VALUE_TYPE_INT32_RANGE: thrift_attr.value.s32range.min = attr.value.s32range.min; thrift_attr.value.s32range.max = attr.value.s32range.max; break; case SAI_ATTR_VALUE_TYPE_UINT16_RANGE_LIST: { for (unsigned int i = 0; i < attr.value.u16rangelist.count; i++) { sai_thrift_u16_range_t range; range.min = attr.value.u16rangelist.list[i].min; range.max = attr.value.u16rangelist.list[i].max; thrift_attr.value.u16rangelist.rangelist.push_back(range); } thrift_attr.value.u16rangelist.count = attr.value.u16rangelist.count; free(attr.value.u16rangelist.list); } break; case SAI_ATTR_VALUE_TYPE_ACL_CAPABILITY: { for (unsigned int i = 0; i < attr.value.aclcapability.action_list.count; i++) { thrift_attr.value.aclcapability.action_list.int32list.push_back(attr.value.aclcapability.action_list.list[i]); } thrift_attr.value.aclcapability.action_list.count = attr.value.aclcapability.action_list.count; free(attr.value.aclcapability.action_list.list); } break; case SAI_ATTR_VALUE_TYPE_ACL_RESOURCE_LIST: { for (unsigned int i = 0; i < attr.value.aclresource.count; i++) { sai_thrift_acl_resource_t resource = {}; resource.stage = attr.value.aclresource.list[i].stage; resource.bind_point = attr.value.aclresource.list[i].bind_point; resource.avail_num = attr.value.aclresource.list[i].avail_num; thrift_attr.value.aclresource.resourcelist.push_back(resource); } thrift_attr.value.aclresource.count = attr.value.aclresource.count; free(attr.value.aclresource.list); } break; case SAI_ATTR_VALUE_TYPE_IP_ADDRESS_LIST: { for (unsigned int i = 0; i < attr.value.ipaddrlist.count; i++) { sai_thrift_ip_address_t thrift_ip; sai_ip_address_t_to_thrift(thrift_ip, attr.value.ipaddrlist.list[i]); thrift_attr.value.ipaddrlist.addresslist.push_back(thrift_ip); } thrift_attr.value.ipaddrlist.count = attr.value.ipaddrlist.count; free(attr.value.ipaddrlist.list); } break; case SAI_ATTR_VALUE_TYPE_IP_PREFIX_LIST: { for (unsigned int i = 0; i < attr.value.ipprefixlist.count; i++) { sai_thrift_ip_prefix_t thrift_ip; sai_ip_prefix_t_to_thrift(thrift_ip, attr.value.ipprefix); thrift_attr.value.ipprefixlist.prefixlist.push_back(thrift_ip); } thrift_attr.value.ipprefixlist.count = attr.value.ipprefixlist.count; free(attr.value.ipprefixlist.list); } break; case SAI_ATTR_VALUE_TYPE_QOS_MAP_LIST: { for (unsigned int i = 0; i < attr.value.qosmap.count; i++) { sai_thrift_qos_map_t thrift_qos_map; // key thrift_qos_map.key.tc = attr.value.qosmap.list[i].key.tc; thrift_qos_map.key.dscp = attr.value.qosmap.list[i].key.dscp; thrift_qos_map.key.dot1p = attr.value.qosmap.list[i].key.dot1p; thrift_qos_map.key.prio = attr.value.qosmap.list[i].key.prio; thrift_qos_map.key.pg = attr.value.qosmap.list[i].key.pg; thrift_qos_map.key.queue_index = attr.value.qosmap.list[i].key.queue_index; thrift_qos_map.key.color = static_cast<int32_t>(attr.value.qosmap.list[i].key.color); thrift_qos_map.key.mpls_exp = attr.value.qosmap.list[i].key.mpls_exp; // value thrift_qos_map.value.tc = attr.value.qosmap.list[i].value.tc; thrift_qos_map.value.dscp = attr.value.qosmap.list[i].value.dscp; thrift_qos_map.value.dot1p = attr.value.qosmap.list[i].value.dot1p; thrift_qos_map.value.prio = attr.value.qosmap.list[i].value.prio; thrift_qos_map.value.pg = attr.value.qosmap.list[i].value.pg; thrift_qos_map.value.queue_index = attr.value.qosmap.list[i].value.queue_index; thrift_qos_map.value.color = static_cast<int32_t>(attr.value.qosmap.list[i].value.color); thrift_qos_map.value.mpls_exp = attr.value.qosmap.list[i].value.mpls_exp; thrift_attr.value.qosmap.maplist.push_back(thrift_qos_map); } thrift_attr.value.qosmap.count = attr.value.qosmap.count; free(attr.value.qosmap.list); } break; default: SAI_META_LOG_ERROR("attr value type not supported for %s", md->attridname); throw e; } } /** * @brief Convert Thrift NAT type to SAI NAT type */ static void sai_thrift_nat_type_t_parse( const sai_thrift_nat_type_t &thrift_nat_type, sai_nat_type_t *nat_type) { *nat_type = (sai_nat_type_t)thrift_nat_type; } // including it here we never have to modify the generated file #include "sai_rpc_server.cpp" class sai_rpcHandlerFrontend: virtual public sai_rpcHandler { /** * @brief Thrift wrapper for sai_object_type_get_availability() SAI function */ int64_t sai_thrift_object_type_get_availability( const sai_thrift_object_type_t object_type, const sai_thrift_attr_id_t attr_id, const int32_t attr_type) override { sai_attribute_t attr; attr.id = attr_id; attr.value.s32 = attr_type; uint32_t attr_count = 1; uint64_t count = 0; sai_object_type_get_availability(switch_id, (sai_object_type_t)object_type, attr_count, &attr, &count); return count; } /** * @brief Thrift wrapper for sai_object_type_query() SAI function */ sai_thrift_object_type_t sai_thrift_object_type_query( const sai_thrift_object_id_t object_id) override { return sai_object_type_query(object_id); } /** * @brief Thrift wrapper for sai_switch_id_query() SAI function */ sai_thrift_object_id_t sai_thrift_switch_id_query( const sai_thrift_object_id_t object_id) override { return sai_switch_id_query(object_id); } /** * @brief Thrift wrapper for sai_api_uninitialize() SAI function */ sai_thrift_status_t sai_thrift_api_uninitialize(void) override { return sai_api_uninitialize(); } /** * @brief Thrift wrapper for sai_query_attribute_enum_values_capability() * function */ void sai_thrift_query_attribute_enum_values_capability( std::vector<int32_t> &thrift_enum_caps, const sai_thrift_object_type_t object_type, const sai_thrift_attr_id_t attr_id, const int32_t caps_count) override { if (!caps_count) { return; } std::vector<int32_t> caps_list(caps_count); sai_s32_list_t enum_values_capability; enum_values_capability.list = caps_list.data(); enum_values_capability.count = caps_count; sai_status_t status = sai_query_attribute_enum_values_capability( (sai_object_id_t)switch_id, (sai_object_type_t)object_type, (sai_attr_id_t)attr_id, &enum_values_capability); if (status == SAI_STATUS_SUCCESS) { for (uint32_t i = 0; i < enum_values_capability.count; ++i) { thrift_enum_caps.push_back(enum_values_capability.list[i]); } } } }; static pthread_mutex_t cookie_mutex; static pthread_cond_t cookie_cv; static void *cookie; /** * @brief Create a Thrift RPC server thread */ static void *sai_thrift_rpc_server_thread(void *arg) { int port = *(int *)arg; std::shared_ptr<sai_rpcHandlerFrontend> handler(new sai_rpcHandlerFrontend()); std::shared_ptr<TProcessor> processor(new sai_rpcProcessor(handler)); std::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port)); std::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory()); std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory()); TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory); pthread_mutex_lock(&cookie_mutex); cookie = (void *)processor.get(); pthread_cond_signal(&cookie_cv); pthread_mutex_unlock(&cookie_mutex); server.serve(); return 0; } static pthread_t sai_thrift_rpc_thread; extern "C" { /** * @brief Start Thrift RPC server */ int start_p4_sai_thrift_rpc_server(char *port) { static int *param = (int *)malloc(sizeof(int)); *param = atoi(port); std::cerr << "Starting SAI RPC server on port " << port << std::endl; cookie = NULL; int status = pthread_create(&sai_thrift_rpc_thread, NULL, sai_thrift_rpc_server_thread, param); if (status) { return status; } pthread_mutex_lock(&cookie_mutex); while (!cookie) { pthread_cond_wait(&cookie_cv, &cookie_mutex); } pthread_mutex_unlock(&cookie_mutex); pthread_mutex_destroy(&cookie_mutex); pthread_cond_destroy(&cookie_cv); return status; } /** * @brief Start Thrift RPC server Wrapper */ int start_sai_thrift_rpc_server(int port) { static char port_str[10]; snprintf(port_str, sizeof(port_str), "%d", port); return start_p4_sai_thrift_rpc_server(port_str); } /** * @brief Stop Thrift RPC server */ int stop_p4_sai_thrift_rpc_server(void) { int status = pthread_cancel(sai_thrift_rpc_thread); if (status == 0) { int s = pthread_join(sai_thrift_rpc_thread, NULL); if (s) { return s; } } return status; } }