Skip to content

sFlow Phase Three Per Port Rate Patch - #261

Open
ritvikiscool9 wants to merge 2 commits into
sonic-net:masterfrom
ritvikiscool9:rituppal-sFlow_phase_three_VPP_plugin_patch
Open

sFlow Phase Three Per Port Rate Patch#261
ritvikiscool9 wants to merge 2 commits into
sonic-net:masterfrom
ritvikiscool9:rituppal-sFlow_phase_three_VPP_plugin_patch

Conversation

@ritvikiscool9

Copy link
Copy Markdown
Contributor

Adds native per-port sample rates to the VPP sflow plugin by moving the random-skip sampling state from per-worker-thread to per-interface.

  • sflow_common.h: adds samplingN, skip, pool, seed to sflow_per_interface_data_t.
  • node.c: identifies the port from the first buffer's sw_if_index (direction-aware: VLIB_TX for egress, else VLIB_RX) and drives sampling off the per-interface skip/pool instead of the per-thread counter. The reported samplingN is the port's own rate (falling back to the global rate).
  • sflow.h: new sflow_next_random_skip_if() helper using the effective rate (per-port, else global).
  • sflow.c: new sflow_set_sampling_rate_set() backend (validates a hardware port, sets the port rate, re-seeds skip), seeds per-port skip on enable, refreshes inheriting ports on a global-rate change, read_node_counters() sums pool per-interface.

samplingN == 0 means inherit the global rate, so unconfigured ports are unchanged (backward compatible). Each port's rate is independent — changing one port doesn't affect others. Pairs with 0013 (direction) and 0014 (API/CLI) to complete Phase 3.

…, rate 0 inherits global. Setter added but API/CLI wiring lands in a follow-up PR.

Signed-off-by: Ritvik Uppal <rituppal@cisco.com>
@mssonicbld

Copy link
Copy Markdown

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

memcpy (sample.header, en, hdr);
if (PREDICT_FALSE (!sflow_fifo_enqueue (&sfwk->fifo, &sample)))
- sfwk->drop++;
+ sfwk->drop++;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check indentation

skipping the rest. */
- sfwk->skip -= pkts;
- sfwk->pool += pkts;
+ sfif->skip -= pkts;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check indentation

+ u32 samplingN;
+ u32 skip;
+ u32 pool;
+ u32 seed;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that skip/pool/seed are per-interface instead of per-thread, multiple VPP threads may touch the same interface at once, causing a data race and miscounts. Can these be indexed per-thread and per-interface so each thread keeps its own counters? samplingN can stay shared since it's only set on the CLI/API path.

@ritvikiscool9
ritvikiscool9 force-pushed the rituppal-sFlow_phase_three_VPP_plugin_patch branch from 503f954 to b5491f4 Compare July 16, 2026 18:36
@mssonicbld

Copy link
Copy Markdown

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@mssonicbld

Copy link
Copy Markdown

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Signed-off-by: Ritvik Uppal <rituppal@cisco.com>
@ritvikiscool9
ritvikiscool9 force-pushed the rituppal-sFlow_phase_three_VPP_plugin_patch branch from 0a4bece to f60d134 Compare July 16, 2026 19:23
@mssonicbld

Copy link
Copy Markdown

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

@sflow

sflow commented Jul 29, 2026

Copy link
Copy Markdown

Moving this comment from the commit thread to the PR thread and expanding it to include more explanation:

This approach is assuming all packets in the frame/vector presented to the worker thread are ingressing from (or egressing to) just one interface. I don't believe this is a safe assumption. To apply sampling on a per-interface basis in the dataplane node would require testing each packet separately, and the extra instructions/branching this would entail is likely to hurt performance significantly. Per-interface sampling rates are not important enough to justify slowing down the forwarding performance of the switch. However I do think we can support it if we adopt a different approach... that will also be easier to implement and test.

So the suggested alternative way to support per-interface sampling rates is as follows:

(1) Leave the data plane as it was. Whole articles were written about that code(!) Best not to touch it. Anything extra you do here will negatively impact the forwarding performance of the switch.
(2) restrict the allowed per-interface sampling rates so that they are required to follow powers of 2. Note that you don't have to push back if the user selects something else - the sFlow standard allows you to run with the nearest (>=) supported sampling rate and that chosen rate is reported in the feed. Many of the ASICs out there have this restriction, so it is well within the rights of the VPP data plane to have a similar restriction.
(3) set the data plane to sample at the highest-common-factor (i.e. the most aggressive sampling rate configured on any port).
(4) in the main thread, skip over unwanted samples on a per-interface basis.

There is one possible drawback that I will address here - what if an aggressive sampling rate is configured on a low-speed port, and a more sparse sampling-rate is configured on a high-speed port? The data-plane will be forced to sample all traffic at the aggressive rate, and there is a risk that too many samples will be generated, so that forwarding performance is affected and the FIFOs carrying samples from worker threads to main thread will start dropping samples, most of which the main thread was about to throw away. The answer is that (a) it is not common for a production switch to be given more than one sampling rate, and if it ever happens the difference is likely to be a factor of 8 or less (e.g. 1-in-1024 on one port and 1-in-8192 on another), and (b) in tests, the mechanism of forwarding samples via dedicated lock-free FIFOs from workers to main thread was efficient, so that the overhead of sending 8x or 16x or even 32x more samples that are actually required for export is not too expensive to accommodate.

So the implementation suggestion is to apply per-interface sub-sampling here:
https://github.com/FDio/vpp/blob/d1b15c1bf4e4046649a797645f9a7fd1a3811282/src/plugins/sflow/sflow.c#L452

You'll need to index into a vector of per-interface state that includes two integers: a worker_samples counter and the sub-sampling rate that should be applied. The sub-sampling rates will need to be recomputed whenever any change is made to the sampling-rate settings in the configuration. You might choose to implement is as a binary mask. So if the sub-sampling rate for interface X is to be 1:8 then the mask will be decimal 8 - 1 = binary 0x0111 and the sub-sampling test will be something like:

if((++itf->worker_samples & itf->sample_mask) == itf->sample_mask) {
    send_packet_sample(...);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants