diff --git a/vslib/vpp/SwitchVpp.h b/vslib/vpp/SwitchVpp.h index b7a75f9e4a..826e259380 100644 --- a/vslib/vpp/SwitchVpp.h +++ b/vslib/vpp/SwitchVpp.h @@ -823,7 +823,6 @@ namespace saivs uint32_t m_acl_default_swindex = 0; bool m_acl_default_created = false; - uint32_t m_sflow_sample_rate = 0; protected: // VPP @@ -1112,6 +1111,13 @@ namespace saivs sai_status_t sflowHostifTableEntryRemove( _In_ const std::string &serializedObjectId); + sai_status_t sflowInterfaceSamplingRateSet( + _In_ sai_object_id_t port_id, + _In_ uint32_t rate); + + sai_status_t sflowInterfaceDirectionSet( + _In_ sai_object_id_t port_id, + _In_ uint32_t direction); public: // VPP diff --git a/vslib/vpp/SwitchVppRif.cpp b/vslib/vpp/SwitchVppRif.cpp index b7e6048c02..1673536518 100644 --- a/vslib/vpp/SwitchVppRif.cpp +++ b/vslib/vpp/SwitchVppRif.cpp @@ -602,6 +602,13 @@ sai_status_t SwitchVpp::UpdatePort( sflowPortSamplePacketSet(object_id, attr_type); } + attr_type = sai_metadata_get_attr_by_id(SAI_PORT_ATTR_EGRESS_SAMPLEPACKET_ENABLE, attr_count, attr_list); + + if(attr_type != NULL) + { + sflowPortSamplePacketSet(object_id, attr_type); + } + attr_type = sai_metadata_get_attr_by_id(SAI_PORT_ATTR_EGRESS_ACL, attr_count, attr_list); if (attr_type != NULL) diff --git a/vslib/vpp/SwitchVppSflow.cpp b/vslib/vpp/SwitchVppSflow.cpp index 1963f39d9c..bdba8d9855 100644 --- a/vslib/vpp/SwitchVppSflow.cpp +++ b/vslib/vpp/SwitchVppSflow.cpp @@ -170,34 +170,121 @@ sai_status_t SwitchVpp::sflowPortSamplePacketSet( { SWSS_LOG_ENTER(); - sai_object_id_t sp_oid = attr->value.oid; + /* + * SAI updates ingress and egress sampling independently, while VPP + * expects one combined per-port direction mask. Use the incoming + * attribute for the direction being updated, retrieve the stored + * attribute for the opposite direction, and combine both before + * programming the exact sampling rate and direction into VPP. + */ + + if(attr->id != SAI_PORT_ATTR_EGRESS_SAMPLEPACKET_ENABLE && attr->id != SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE) + { + SWSS_LOG_ERROR("Unexpected sFlow port attribute ID %u", attr->id); + return SAI_STATUS_INVALID_PARAMETER; + } + + bool updating_ingress = attr->id == SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE; + sai_object_id_t updated_oid = attr->value.oid; + + sai_attribute_t other_attr{}; + + other_attr.id = updating_ingress + ? SAI_PORT_ATTR_EGRESS_SAMPLEPACKET_ENABLE + : SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE; + sai_object_id_t other_oid = SAI_NULL_OBJECT_ID; + + if (get(SAI_OBJECT_TYPE_PORT, portId, 1, &other_attr) == SAI_STATUS_SUCCESS) + { + other_oid = other_attr.value.oid; + } + + sai_object_id_t ingress_oid = updating_ingress ? updated_oid : other_oid; + sai_object_id_t egress_oid = updating_ingress ? other_oid : updated_oid; - if(sp_oid == SAI_NULL_OBJECT_ID) + constexpr uint32_t SFLOW_DIRECTION_INGRESS = 1U; + constexpr uint32_t SFLOW_DIRECTION_EGRESS = 2U; + uint32_t direction = 0; + + if(ingress_oid != SAI_NULL_OBJECT_ID) + { + direction |= SFLOW_DIRECTION_INGRESS; + } + + if(egress_oid != SAI_NULL_OBJECT_ID) + { + direction |= SFLOW_DIRECTION_EGRESS; + } + + if (direction == 0) { return sflowEnableDisable(portId, false); } - sai_attribute_t rate_attr; + sai_object_id_t active_oid = updated_oid != SAI_NULL_OBJECT_ID ? updated_oid : other_oid; + + auto serialized_id = sai_serialize_object_id(active_oid); + + sai_attribute_t rate_attr{}; rate_attr.id = SAI_SAMPLEPACKET_ATTR_SAMPLE_RATE; - uint32_t rate = 0; - auto serialized_id = sai_serialize_object_id(sp_oid); + CHECK_STATUS(get(SAI_OBJECT_TYPE_SAMPLEPACKET, serialized_id, 1, &rate_attr)); + + uint32_t rate = rate_attr.value.u32; + + CHECK_STATUS(sflowInterfaceSamplingRateSet(portId, rate)); + CHECK_STATUS(sflowInterfaceDirectionSet(portId, direction)); + return sflowEnableDisable(portId, true); +} - if (get(SAI_OBJECT_TYPE_SAMPLEPACKET, serialized_id, 1, &rate_attr) == SAI_STATUS_SUCCESS) +sai_status_t SwitchVpp::sflowInterfaceSamplingRateSet( + _In_ sai_object_id_t port_id, + _In_ uint32_t rate) +{ + SWSS_LOG_ENTER(); + + std::string if_name; + + if(!port_to_hwifname(port_id, if_name)) + { + SWSS_LOG_ERROR("failed to get hwif name for port %s", sai_serialize_object_id(port_id).c_str()); + return SAI_STATUS_FAILURE; + } + + int ret = vpp_sflow_interface_sampling_rate_set(if_name.c_str(), rate); + if (ret != 0) + { + SWSS_LOG_ERROR("sflow sampling rate set failed for port %s, status %d", sai_serialize_object_id(port_id).c_str(), ret); + return SAI_STATUS_FAILURE; + } + + SWSS_LOG_NOTICE("Changed sampling rate to 1-in-%d for port %s", rate, sai_serialize_object_id(port_id).c_str()); + + return SAI_STATUS_SUCCESS; +} + +sai_status_t SwitchVpp::sflowInterfaceDirectionSet( + _In_ sai_object_id_t port_id, + _In_ uint32_t direction) +{ + SWSS_LOG_ENTER(); + + std::string if_name; + + if(!port_to_hwifname(port_id, if_name)) { - rate = rate_attr.value.u32; + SWSS_LOG_ERROR("failed to get hwif name for port %s", sai_serialize_object_id(port_id).c_str()); + return SAI_STATUS_FAILURE; } - if (m_sflow_sample_rate != 0 && m_sflow_sample_rate != rate) + int ret = vpp_sflow_interface_direction_set(if_name.c_str(), direction); + if (ret != 0) { - SWSS_LOG_WARN("sFlow sample rate mismatch: global=%u port %s requesting=%u (last-writer-wins)", - m_sflow_sample_rate, - sai_serialize_object_id(portId).c_str(), - rate); + SWSS_LOG_ERROR("sflow direction set failed for port %s, status %d", sai_serialize_object_id(port_id).c_str(), ret); + return SAI_STATUS_FAILURE; } - m_sflow_sample_rate = rate; + SWSS_LOG_NOTICE("Changed direction for port %s", sai_serialize_object_id(port_id).c_str()); - CHECK_STATUS(sflowEnableDisable(portId, true)); - return sflowSamplingRateSet(rate); + return SAI_STATUS_SUCCESS; } \ No newline at end of file diff --git a/vslib/vpp/vppxlate/SaiVppXlate.c b/vslib/vpp/vppxlate/SaiVppXlate.c index 1308cdabf1..1a9b30d702 100644 --- a/vslib/vpp/vppxlate/SaiVppXlate.c +++ b/vslib/vpp/vppxlate/SaiVppXlate.c @@ -1252,6 +1252,20 @@ vl_api_bfd_udp_set_tos_reply_t_handler (vl_api_bfd_udp_set_tos_reply_t *msg) set_reply_status(retval); } +static void +vl_api_sflow_interface_sampling_rate_set_reply_t_handler(vl_api_sflow_interface_sampling_rate_set_reply_t *msg) +{ + int retval = (int)ntohl((uint32_t)msg->retval); + set_reply_status(retval); +} + +static void +vl_api_sflow_interface_direction_set_reply_t_handler(vl_api_sflow_interface_direction_set_reply_t *msg) +{ + int retval = (int)ntohl((uint32_t)msg->retval); + set_reply_status(retval); +} + static void vl_api_bfd_udp_session_event_t_handler (vl_api_bfd_udp_session_event_t *msg) { @@ -1780,6 +1794,8 @@ vl_api_acl_interface_add_del_reply_t_handler(vl_api_acl_interface_add_del_reply_ _(SR_MSG_ID(SR_SET_ENCAP_SOURCE_REPLY), sr_set_encap_source_reply) \ _(SFLOW_MSG_ID(SFLOW_ENABLE_DISABLE_REPLY), sflow_enable_disable_reply) \ _(SFLOW_MSG_ID(SFLOW_SAMPLING_RATE_SET_REPLY), sflow_sampling_rate_set_reply) \ + _(SFLOW_MSG_ID(SFLOW_INTERFACE_SAMPLING_RATE_SET_REPLY), sflow_interface_sampling_rate_set_reply) \ + _(SFLOW_MSG_ID(SFLOW_INTERFACE_DIRECTION_SET_REPLY), sflow_interface_direction_set_reply) \ _(IPIP_MSG_ID(IPIP_ADD_TUNNEL_REPLY), ipip_add_tunnel_reply) \ _(IPIP_MSG_ID(IPIP_DEL_TUNNEL_REPLY), ipip_del_tunnel_reply) @@ -3191,6 +3207,87 @@ int vpp_ip_flow_hash_set (uint32_t vrf_id, uint32_t hash_mask, int addr_family) return ret; } +int vpp_sflow_interface_sampling_rate_set(const char *hwif_name, uint32_t sampling_n) +{ + vat_main_t *vam = &vat_main; + vl_api_sflow_interface_sampling_rate_set_t *mp; + int ret; + + VPP_LOCK(); + + __plugin_msg_base = sflow_msg_id_base; + M(SFLOW_INTERFACE_SAMPLING_RATE_SET, mp); + + if(hwif_name){ + u32 idx = get_swif_idx(vam, hwif_name); + if(idx != (u32) - 1){ + mp->hw_if_index = htonl(idx); + } else { + SAIVPP_ERROR("Unable to get the sw_index for %s\n", hwif_name); + VPP_UNLOCK(); + return -EINVAL; + } + } else { + SAIVPP_ERROR("No hw_index provided"); + VPP_UNLOCK(); + return -EINVAL; + } + + mp->sampling_N = htonl(sampling_n); + + S(mp); + WR(ret); + + if (ret) { + SAIVPP_ERROR("%s failed(%d) %s sampling_N %u", __func__, ret, hwif_name, sampling_n); + } else { + SAIVPP_INFO("%s %s sampling_N %u", __func__, hwif_name, sampling_n); + } + + VPP_UNLOCK(); + return ret; +} + +int vpp_sflow_interface_direction_set(const char *hwif_name, uint32_t direction) +{ + vat_main_t *vam = &vat_main; + vl_api_sflow_interface_direction_set_t *mp; + int ret; + + VPP_LOCK(); + + __plugin_msg_base = sflow_msg_id_base; + M(SFLOW_INTERFACE_DIRECTION_SET, mp); + + if(hwif_name){ + u32 idx = get_swif_idx(vam, hwif_name); + if(idx != (u32) - 1){ + mp->hw_if_index = htonl(idx); + } else { + SAIVPP_ERROR("Unable to get the sw_index for %s\n", hwif_name); + VPP_UNLOCK(); + return -EINVAL; + } + } else { + SAIVPP_ERROR("No hw_index provided"); + VPP_UNLOCK(); + return -EINVAL; + } + + mp->direction = htonl(direction); + + S(mp); + WR(ret); + + if (ret) { + SAIVPP_ERROR("%s failed(%d) %s direction %u", __func__, ret, hwif_name, direction); + } else { + SAIVPP_INFO("%s %s direction %u", __func__, hwif_name, direction); + } + + VPP_UNLOCK(); + return ret; +} /* * Set the global ECMP flow-hash "router ID" -- the per-router value VPP mixes * into the IPv4/IPv6 ECMP flow hash (see ip4_inlines.h / ip6_inlines.h: diff --git a/vslib/vpp/vppxlate/SaiVppXlate.h b/vslib/vpp/vppxlate/SaiVppXlate.h index 7f6ac1e898..554228571c 100644 --- a/vslib/vpp/vppxlate/SaiVppXlate.h +++ b/vslib/vpp/vppxlate/SaiVppXlate.h @@ -407,6 +407,8 @@ typedef enum { extern int vpp_sw_interface_find_by_ip(vpp_ip_addr_t *search_ip, uint32_t vrf_id, uint32_t *out_sw_if_index); + extern int vpp_sflow_interface_sampling_rate_set(const char *hwif_name, uint32_t sampling_n); + extern int vpp_sflow_interface_direction_set(const char *hwif_name, uint32_t direction); /* VPP Classify API for L2 punt */ extern int vpp_classify_table_create(uint32_t nbuckets, uint32_t memory_size,