Skip to content

Commit

Permalink
support sflow on virtual switch (#498)
Browse files Browse the repository at this point in the history
When sflow is configured using CLI or other supported mechanisms, the orch-agent invokes
the SAI API set_port_attribute(). For the sflow feature, his API is used to set the SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE attribute of a netdev port. The value stored for this attribute is a samplepacket object, which essentially contains various sampling attributes (sampling rate, sampler group etc.) associated with the port.

When sampling is disabled on a port, the SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE attribute is set to a null object.
When sampling is enabled on a port, the SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE attribute is set to a valid samplepacket object.

For sonic-vs, in the absence of a real ASIC programming, the 'tc' command is used instead to configure the sampling parameters inside the kernel. In this PR we invoke the appropriate 'tc' command, based on the requested config actions (disable or enable or update).

Signed-off-by: Rakesh Datta <rakesh.datta@dell.com>
  • Loading branch information
Rakesh Datta authored and lguohan committed Sep 15, 2019
1 parent e7d766e commit 38c6945
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 2 deletions.
25 changes: 24 additions & 1 deletion vslib/inc/sai_vs_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,34 @@ class SwitchState
return it->second;
}

void setTapNameToPortId(
_In_ const std::string& tapname,
_In_ sai_object_id_t port_id)
{
SWSS_LOG_ENTER();

m_port_id_to_tapname[port_id] = tapname;
}

bool getTapNameFromPortId(
_In_ const sai_object_id_t port_id,
_Out_ std::string& if_name)
{
SWSS_LOG_ENTER();

if (m_port_id_to_tapname.find(port_id) != m_port_id_to_tapname.end())
{
if_name = m_port_id_to_tapname[port_id];
return true;
}
return false;
}

private:

sai_object_id_t m_switch_id;

std::map<std::string, sai_object_id_t> m_ifname_to_port_id;
std::map<sai_object_id_t, std::string> m_port_id_to_tapname;

swss::SelectableEvent m_link_thread_event;

Expand Down
1 change: 1 addition & 0 deletions vslib/src/sai_vs_hostintf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,7 @@ sai_status_t vs_create_hostif_tap_interface(

g_switch_state_map.at(switch_id)->setIfNameToPortId(vname, obj_id);

g_switch_state_map.at(switch_id)->setTapNameToPortId(name, obj_id);
// TODO what about FDB entries notifications, they also should
// be generated if new mac address will show up on the interface/arp table

Expand Down
132 changes: 131 additions & 1 deletion vslib/src/sai_vs_port.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,138 @@ sai_status_t vs_create_port(
return SAI_STATUS_SUCCESS;
}

sai_status_t vs_set_port_attribute(
_In_ sai_object_id_t port_id,
_In_ const sai_attribute_t *attr)
{
MUTEX();
SWSS_LOG_ENTER();

std::string cmd;

// Special handling for the sampling attribute modification
if (attr->id == SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE)
{
// Get the sample-packet object id
sai_object_id_t samplepacket_oid = attr->value.oid;

// Get the interface name from the port id
std::string if_name;

sai_object_id_t vs_switch_id = sai_switch_id_query(port_id);
if (vs_switch_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("vs_switch_id is null");
return SAI_STATUS_FAILURE;
}

auto it = g_switch_state_map.find(vs_switch_id);
if (it == g_switch_state_map.end())
{
SWSS_LOG_ERROR("No switch state found for the switch id %s",
sai_serialize_object_id(vs_switch_id).c_str());
return SAI_STATUS_FAILURE;
}

auto sw = it->second;
if (sw == nullptr)
{
SWSS_LOG_ERROR("switch state for the switch id %s is null",
sai_serialize_object_id(vs_switch_id).c_str());
return SAI_STATUS_FAILURE;
}

if (sw->getTapNameFromPortId(port_id, if_name) == false)
{
SWSS_LOG_ERROR("tap interface name corresponding to the port id %s is not found",
sai_serialize_object_id(port_id).c_str());
return SAI_STATUS_FAILURE;
}

if (samplepacket_oid == SAI_NULL_OBJECT_ID)
{
//Delete the sampling session
cmd.assign("tc qdisc delete dev " + if_name + " handle ffff: ingress");
if (system(cmd.c_str()) == -1)
{
SWSS_LOG_ERROR("unable to delete the sampling session \
for the interface %s",if_name);
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
return SAI_STATUS_FAILURE;
}
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
} else {
//Get the sample rate from the sample object
sai_attribute_t samplepacket_attr;
samplepacket_attr.id = SAI_SAMPLEPACKET_ATTR_SAMPLE_RATE;

if (SAI_STATUS_SUCCESS == \
vs_generic_get(SAI_OBJECT_TYPE_SAMPLEPACKET, samplepacket_oid, 1, &samplepacket_attr))
{
int rate = samplepacket_attr.value.u32;

//Set the default sample group ID
std::string group("1");

//Check if sampling is already enabled on the port
sai_attribute_t port_attr;
port_attr.id = SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE;

// When the sampling parameters are updated,
// a delete and add operation is performed on the sampling session.
// If the sampling session is already created, it is deleted below.
if ((vs_generic_get(SAI_OBJECT_TYPE_PORT, port_id, 1, &port_attr) \
== SAI_STATUS_SUCCESS) && (port_attr.value.oid != SAI_NULL_OBJECT_ID))
{
//Sampling session is already created
SWSS_LOG_INFO("sampling is already enabled on the port: %s .. Deleting it", \
sai_serialize_object_id(port_id).c_str());

//Delete the sampling session
cmd.assign("tc qdisc delete dev " + if_name + " handle ffff: ingress");
if (system(cmd.c_str()) == -1){
SWSS_LOG_ERROR("unable to delete the sampling session \
for the interface %s",if_name);
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
return SAI_STATUS_FAILURE;
}
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
}

//Create a new sampling session
cmd.assign("tc qdisc add dev " + if_name + " handle ffff: ingress");
if (system(cmd.c_str()) == -1)
{
SWSS_LOG_ERROR("unable to create a sampling session for the interface %s", if_name);
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
return SAI_STATUS_FAILURE;
}
SWSS_LOG_INFO("successfully applied the command: %s", cmd);

//Set the sampling rate of the port
cmd.assign("tc filter add dev " + if_name + \
" parent ffff: matchall action sample rate " + std::to_string(rate) + \
" group " + group);
if (system(cmd.c_str()) == -1)
{
SWSS_LOG_ERROR("unable to update the sampling rate of the interface %s",if_name);
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
return SAI_STATUS_FAILURE;
}
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
} else {
SWSS_LOG_ERROR("failed to update the port %s, unable to read the sample attr", if_name);
return SAI_STATUS_FAILURE;
}
}
SWSS_LOG_INFO("successfully modified the sampling config of the port: %s",
sai_serialize_object_id(port_id).c_str());
}

return meta_sai_set_oid((sai_object_type_t)SAI_OBJECT_TYPE_PORT, port_id, attr, &vs_generic_set);
}

VS_REMOVE(PORT,port);
VS_SET(PORT,port);
VS_GET(PORT,port);
VS_GENERIC_QUAD(PORT_POOL,port_pool);
VS_GENERIC_STATS(PORT,port);
Expand Down

0 comments on commit 38c6945

Please sign in to comment.