Skip to content
8 changes: 7 additions & 1 deletion vslib/vpp/SwitchVpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
7 changes: 7 additions & 0 deletions vslib/vpp/SwitchVppRif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
117 changes: 102 additions & 15 deletions vslib/vpp/SwitchVppSflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
97 changes: 97 additions & 0 deletions vslib/vpp/vppxlate/SaiVppXlate.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions vslib/vpp/vppxlate/SaiVppXlate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading