Skip to content

Commit 38c6945

Browse files
Rakesh Dattalguohan
authored andcommitted
support sflow on virtual switch (sonic-net#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 <[email protected]>
1 parent e7d766e commit 38c6945

File tree

3 files changed

+156
-2
lines changed

3 files changed

+156
-2
lines changed

vslib/inc/sai_vs_state.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,34 @@ class SwitchState
253253
return it->second;
254254
}
255255

256+
void setTapNameToPortId(
257+
_In_ const std::string& tapname,
258+
_In_ sai_object_id_t port_id)
259+
{
260+
SWSS_LOG_ENTER();
261+
262+
m_port_id_to_tapname[port_id] = tapname;
263+
}
264+
265+
bool getTapNameFromPortId(
266+
_In_ const sai_object_id_t port_id,
267+
_Out_ std::string& if_name)
268+
{
269+
SWSS_LOG_ENTER();
270+
271+
if (m_port_id_to_tapname.find(port_id) != m_port_id_to_tapname.end())
272+
{
273+
if_name = m_port_id_to_tapname[port_id];
274+
return true;
275+
}
276+
return false;
277+
}
278+
256279
private:
257280

258281
sai_object_id_t m_switch_id;
259282

260-
std::map<std::string, sai_object_id_t> m_ifname_to_port_id;
283+
std::map<sai_object_id_t, std::string> m_port_id_to_tapname;
261284

262285
swss::SelectableEvent m_link_thread_event;
263286

vslib/src/sai_vs_hostintf.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,7 @@ sai_status_t vs_create_hostif_tap_interface(
12341234

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

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

vslib/src/sai_vs_port.cpp

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,138 @@ sai_status_t vs_create_port(
3939
return SAI_STATUS_SUCCESS;
4040
}
4141

42+
sai_status_t vs_set_port_attribute(
43+
_In_ sai_object_id_t port_id,
44+
_In_ const sai_attribute_t *attr)
45+
{
46+
MUTEX();
47+
SWSS_LOG_ENTER();
48+
49+
std::string cmd;
50+
51+
// Special handling for the sampling attribute modification
52+
if (attr->id == SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE)
53+
{
54+
// Get the sample-packet object id
55+
sai_object_id_t samplepacket_oid = attr->value.oid;
56+
57+
// Get the interface name from the port id
58+
std::string if_name;
59+
60+
sai_object_id_t vs_switch_id = sai_switch_id_query(port_id);
61+
if (vs_switch_id == SAI_NULL_OBJECT_ID)
62+
{
63+
SWSS_LOG_ERROR("vs_switch_id is null");
64+
return SAI_STATUS_FAILURE;
65+
}
66+
67+
auto it = g_switch_state_map.find(vs_switch_id);
68+
if (it == g_switch_state_map.end())
69+
{
70+
SWSS_LOG_ERROR("No switch state found for the switch id %s",
71+
sai_serialize_object_id(vs_switch_id).c_str());
72+
return SAI_STATUS_FAILURE;
73+
}
74+
75+
auto sw = it->second;
76+
if (sw == nullptr)
77+
{
78+
SWSS_LOG_ERROR("switch state for the switch id %s is null",
79+
sai_serialize_object_id(vs_switch_id).c_str());
80+
return SAI_STATUS_FAILURE;
81+
}
82+
83+
if (sw->getTapNameFromPortId(port_id, if_name) == false)
84+
{
85+
SWSS_LOG_ERROR("tap interface name corresponding to the port id %s is not found",
86+
sai_serialize_object_id(port_id).c_str());
87+
return SAI_STATUS_FAILURE;
88+
}
89+
90+
if (samplepacket_oid == SAI_NULL_OBJECT_ID)
91+
{
92+
//Delete the sampling session
93+
cmd.assign("tc qdisc delete dev " + if_name + " handle ffff: ingress");
94+
if (system(cmd.c_str()) == -1)
95+
{
96+
SWSS_LOG_ERROR("unable to delete the sampling session \
97+
for the interface %s",if_name);
98+
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
99+
return SAI_STATUS_FAILURE;
100+
}
101+
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
102+
} else {
103+
//Get the sample rate from the sample object
104+
sai_attribute_t samplepacket_attr;
105+
samplepacket_attr.id = SAI_SAMPLEPACKET_ATTR_SAMPLE_RATE;
106+
107+
if (SAI_STATUS_SUCCESS == \
108+
vs_generic_get(SAI_OBJECT_TYPE_SAMPLEPACKET, samplepacket_oid, 1, &samplepacket_attr))
109+
{
110+
int rate = samplepacket_attr.value.u32;
111+
112+
//Set the default sample group ID
113+
std::string group("1");
114+
115+
//Check if sampling is already enabled on the port
116+
sai_attribute_t port_attr;
117+
port_attr.id = SAI_PORT_ATTR_INGRESS_SAMPLEPACKET_ENABLE;
118+
119+
// When the sampling parameters are updated,
120+
// a delete and add operation is performed on the sampling session.
121+
// If the sampling session is already created, it is deleted below.
122+
if ((vs_generic_get(SAI_OBJECT_TYPE_PORT, port_id, 1, &port_attr) \
123+
== SAI_STATUS_SUCCESS) && (port_attr.value.oid != SAI_NULL_OBJECT_ID))
124+
{
125+
//Sampling session is already created
126+
SWSS_LOG_INFO("sampling is already enabled on the port: %s .. Deleting it", \
127+
sai_serialize_object_id(port_id).c_str());
128+
129+
//Delete the sampling session
130+
cmd.assign("tc qdisc delete dev " + if_name + " handle ffff: ingress");
131+
if (system(cmd.c_str()) == -1){
132+
SWSS_LOG_ERROR("unable to delete the sampling session \
133+
for the interface %s",if_name);
134+
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
135+
return SAI_STATUS_FAILURE;
136+
}
137+
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
138+
}
139+
140+
//Create a new sampling session
141+
cmd.assign("tc qdisc add dev " + if_name + " handle ffff: ingress");
142+
if (system(cmd.c_str()) == -1)
143+
{
144+
SWSS_LOG_ERROR("unable to create a sampling session for the interface %s", if_name);
145+
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
146+
return SAI_STATUS_FAILURE;
147+
}
148+
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
149+
150+
//Set the sampling rate of the port
151+
cmd.assign("tc filter add dev " + if_name + \
152+
" parent ffff: matchall action sample rate " + std::to_string(rate) + \
153+
" group " + group);
154+
if (system(cmd.c_str()) == -1)
155+
{
156+
SWSS_LOG_ERROR("unable to update the sampling rate of the interface %s",if_name);
157+
SWSS_LOG_ERROR("failed to apply the command: %s",cmd);
158+
return SAI_STATUS_FAILURE;
159+
}
160+
SWSS_LOG_INFO("successfully applied the command: %s", cmd);
161+
} else {
162+
SWSS_LOG_ERROR("failed to update the port %s, unable to read the sample attr", if_name);
163+
return SAI_STATUS_FAILURE;
164+
}
165+
}
166+
SWSS_LOG_INFO("successfully modified the sampling config of the port: %s",
167+
sai_serialize_object_id(port_id).c_str());
168+
}
169+
170+
return meta_sai_set_oid((sai_object_type_t)SAI_OBJECT_TYPE_PORT, port_id, attr, &vs_generic_set);
171+
}
172+
42173
VS_REMOVE(PORT,port);
43-
VS_SET(PORT,port);
44174
VS_GET(PORT,port);
45175
VS_GENERIC_QUAD(PORT_POOL,port_pool);
46176
VS_GENERIC_STATS(PORT,port);

0 commit comments

Comments
 (0)