From 38c6945bdd9d8c83ee003fe29d036b16b4fb99e6 Mon Sep 17 00:00:00 2001 From: Rakesh Datta Date: Sat, 14 Sep 2019 20:34:54 -0700 Subject: [PATCH] support sflow on virtual switch (#498) 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 --- vslib/inc/sai_vs_state.h | 25 ++++++- vslib/src/sai_vs_hostintf.cpp | 1 + vslib/src/sai_vs_port.cpp | 132 +++++++++++++++++++++++++++++++++- 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/vslib/inc/sai_vs_state.h b/vslib/inc/sai_vs_state.h index e62668e60f46..039e58fd0a23 100644 --- a/vslib/inc/sai_vs_state.h +++ b/vslib/inc/sai_vs_state.h @@ -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 m_ifname_to_port_id; + std::map m_port_id_to_tapname; swss::SelectableEvent m_link_thread_event; diff --git a/vslib/src/sai_vs_hostintf.cpp b/vslib/src/sai_vs_hostintf.cpp index 98345e1cc608..089193c630c8 100644 --- a/vslib/src/sai_vs_hostintf.cpp +++ b/vslib/src/sai_vs_hostintf.cpp @@ -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 diff --git a/vslib/src/sai_vs_port.cpp b/vslib/src/sai_vs_port.cpp index 2c599082defb..f5824d1b1f7d 100644 --- a/vslib/src/sai_vs_port.cpp +++ b/vslib/src/sai_vs_port.cpp @@ -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);