diff --git a/console/data/docs/99-changelog.md b/console/data/docs/99-changelog.md index dc720c24..e28476b5 100644 --- a/console/data/docs/99-changelog.md +++ b/console/data/docs/99-changelog.md @@ -16,6 +16,7 @@ identified with a specific icon: - 🩹 *outlet*: fix gNMI metadata provider exiting too early - 🩹 *doc*: fix documentation for SNMPv3 configuration - 🌱 *inlet*: add support for RFC 5103 (bidirectional flows) +- 🌱 *outlet*: handle discard and multiple interfaces for expanded sFlow samples ## 2.0.0 - 2025-09-22 diff --git a/outlet/flow/decoder/sflow/decode.go b/outlet/flow/decoder/sflow/decode.go index 812cf2f3..4718289e 100644 --- a/outlet/flow/decoder/sflow/decode.go +++ b/outlet/flow/decoder/sflow/decode.go @@ -14,6 +14,18 @@ import ( "github.com/netsampler/goflow2/v2/decoders/sflow" ) +const ( + // interfaceLocal is used for InIf and OutIf when the traffic is + // locally originated or terminated. We need to translate it to 0. + interfaceLocal = 0x3fffffff + // interfaceFormatIfIndex is used when the interface is an index + interfaceFormatIfIndex = 0 + // interfaceFormatDiscard is used for OutIf when the traffic is discarded + interfaceFormatDiscard = 1 + // interfaceFomratMultiple is used when there are multiple output interfaces + interfaceFormatMultiple = 2 +) + func (nd *Decoder) decode(packet sflow.Packet, bf *schema.FlowMessage, finalize decoder.FinalizeFlowFunc) error { for _, flowSample := range packet.Samples { var records []sflow.FlowRecord @@ -22,20 +34,31 @@ func (nd *Decoder) decode(packet sflow.Packet, bf *schema.FlowMessage, finalize case sflow.FlowSample: records = flowSample.Records bf.SamplingRate = uint64(flowSample.SamplingRate) - bf.InIf = flowSample.Input - bf.OutIf = flowSample.Output - switch bf.OutIf & interfaceOutMask { - case interfaceOutDiscard: - bf.OutIf = 0 + switch flowSample.Input >> 30 { + case interfaceFormatIfIndex: + bf.InIf = flowSample.Input + } + switch flowSample.Output >> 30 { + case interfaceFormatIfIndex: + bf.OutIf = flowSample.Output + case interfaceFormatDiscard: forwardingStatus = 128 - case interfaceOutMultiple: - bf.OutIf = 0 + case interfaceFormatMultiple: } case sflow.ExpandedFlowSample: records = flowSample.Records bf.SamplingRate = uint64(flowSample.SamplingRate) - bf.InIf = flowSample.InputIfValue - bf.OutIf = flowSample.OutputIfValue + switch flowSample.InputIfFormat { + case interfaceFormatIfIndex: + bf.InIf = flowSample.InputIfValue + } + switch flowSample.OutputIfFormat { + case interfaceFormatIfIndex: + bf.OutIf = flowSample.OutputIfValue + case interfaceFormatDiscard: + forwardingStatus = 128 + case interfaceFormatMultiple: + } } if bf.InIf == interfaceLocal { diff --git a/outlet/flow/decoder/sflow/root.go b/outlet/flow/decoder/sflow/root.go index 73782339..5f64f7fb 100644 --- a/outlet/flow/decoder/sflow/root.go +++ b/outlet/flow/decoder/sflow/root.go @@ -17,18 +17,6 @@ import ( "akvorado/outlet/flow/decoder" ) -const ( - // interfaceLocal is used for InIf and OutIf when the traffic is - // locally originated or terminated. We need to translate it to 0. - interfaceLocal = 0x3fffffff - // interfaceOutMask is the mask to interpret output interface type - interfaceOutMask = 0xc0000000 - // interfaceOutDiscard is used for OutIf when the traffic is discarded - interfaceOutDiscard = 0x40000000 - // interfaceOutMultiple is used when there are multiple output interfaces - interfaceOutMultiple = 0x80000000 -) - // Decoder contains the state for the sFlow v5 decoder. type Decoder struct { r *reporter.Reporter