From 203b5a8bb2d4185529381b0fa845cf14c4708567 Mon Sep 17 00:00:00 2001 From: Ritvik Uppal Date: Mon, 27 Jul 2026 07:49:19 -0700 Subject: [PATCH 1/2] mod_vpp: don't re-sample PSAMPLE when osIndex=on When osIndex=on, VPP writes the Linux ifIndex into the PSAMPLE metadata and mod_psample already emits the flow sample in that namespace. mod_vpp's evt_psample() then calls takeSample() a second time, so every flow sample is duplicated at the collector (2x) while the VPP plugin's own counter shows 1x. Return early in that mode and let mod_psample own the flow sample; mod_vpp still provides VPP interface counter samples via its netlink channel. --- src/Linux/mod_vpp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Linux/mod_vpp.c b/src/Linux/mod_vpp.c index 88fb8ec..8c9215a 100644 --- a/src/Linux/mod_vpp.c +++ b/src/Linux/mod_vpp.c @@ -542,6 +542,15 @@ v */ static void evt_psample(EVMod *mod, EVEvent *evt, void *data, size_t dataLen) { HSP_mod_VPP *mdata = (HSP_mod_VPP *)mod->data; HSP *sp = (HSP *)EVROOTDATA(mod); + // When osIndex=on, VPP stamps the Linux/SONiC ifIndex directly into the + // PSAMPLE metadata, so mod_psample already emits each flow sample in the + // correct ifIndex namespace (1:1). Sampling again here duplicates every + // flow sample at the collector (the "2x" seen on SONiC-VPP). Let mod_psample + // own flow samples in this mode, mod_vpp still contributes VPP interface + // counter samples via its own netlink channel. + if(sp->vpp.osIndex){ + return; + } HSPPSample *psmp = (HSPPSample *)data; if(psmp->grp_no == SFLOW_VPP_PSAMPLE_GROUP_INGRESS || psmp->grp_no == SFLOW_VPP_PSAMPLE_GROUP_EGRESS) { From 2a476656847607244166e4087c06f8d16d3931c3 Mon Sep 17 00:00:00 2001 From: Ritvik Uppal Date: Mon, 27 Jul 2026 12:50:48 -0700 Subject: [PATCH 2/2] Modifying the guard to allow egress packets to be sampled --- src/Linux/mod_vpp.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Linux/mod_vpp.c b/src/Linux/mod_vpp.c index 8c9215a..32977ab 100644 --- a/src/Linux/mod_vpp.c +++ b/src/Linux/mod_vpp.c @@ -542,16 +542,14 @@ v */ static void evt_psample(EVMod *mod, EVEvent *evt, void *data, size_t dataLen) { HSP_mod_VPP *mdata = (HSP_mod_VPP *)mod->data; HSP *sp = (HSP *)EVROOTDATA(mod); - // When osIndex=on, VPP stamps the Linux/SONiC ifIndex directly into the - // PSAMPLE metadata, so mod_psample already emits each flow sample in the - // correct ifIndex namespace (1:1). Sampling again here duplicates every - // flow sample at the collector (the "2x" seen on SONiC-VPP). Let mod_psample - // own flow samples in this mode, mod_vpp still contributes VPP interface - // counter samples via its own netlink channel. - if(sp->vpp.osIndex){ + HSPPSample *psmp = (HSPPSample *)data; + // When osIndex=on, mod_psample already emits the INGRESS flow sample in the + // Linux/SONiC namespace, so re-sampling ingress here duplicates it (the 2x). + // Egress samples, however, are produced ONLY here — mod_psample's PSAMPLE + // egress group is not enabled in SONiC-VPP — so egress must still be handled. + if(sp->vpp.osIndex && psmp->grp_no == SFLOW_VPP_PSAMPLE_GROUP_INGRESS){ return; } - HSPPSample *psmp = (HSPPSample *)data; if(psmp->grp_no == SFLOW_VPP_PSAMPLE_GROUP_INGRESS || psmp->grp_no == SFLOW_VPP_PSAMPLE_GROUP_EGRESS) { EVDebug(mod, 3, "Got VPP PSample");