mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
outlet/core: accept flows where interface names are missing
This matches the pre-2.0.0 behavior. This may not be a bug, but the idea is that one interface is enough to be valid. Some implementations seem to use bogus indexes. See https://github.com/akvorado/akvorado/discussions/1998#discussioncomment-14992940
This commit is contained in:
@@ -17,6 +17,7 @@ identified with a specific icon:
|
|||||||
false by default)
|
false by default)
|
||||||
- 🩹 *outlet*: provide additional gracetime for a worker to send to ClickHouse
|
- 🩹 *outlet*: provide additional gracetime for a worker to send to ClickHouse
|
||||||
- 🩹 *outlet*: enhance scaling up and down workers to avoid hysteresis
|
- 🩹 *outlet*: enhance scaling up and down workers to avoid hysteresis
|
||||||
|
- 🩹 *outlet*: accept flows where interface names or descriptions are missing
|
||||||
- 🩹 *docker*: update Traefik to 3.6.1 (for compatibility with Docker Engine 29)
|
- 🩹 *docker*: update Traefik to 3.6.1 (for compatibility with Docker Engine 29)
|
||||||
- 🌱 *common*: enable block and mutex profiling
|
- 🌱 *common*: enable block and mutex profiling
|
||||||
- 🌱 *config*: rename `verify` to `skip-verify` in TLS configurations for
|
- 🌱 *config*: rename `verify` to `skip-verify` in TLS configurations for
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ func (w *worker) enrichFlow(exporterIP netip.Addr, exporterStr string) bool {
|
|||||||
|
|
||||||
if flow.InIf != 0 {
|
if flow.InIf != 0 {
|
||||||
answer := c.d.Metadata.Lookup(t, exporterIP, uint(flow.InIf))
|
answer := c.d.Metadata.Lookup(t, exporterIP, uint(flow.InIf))
|
||||||
if !answer.Found {
|
if answer.Found {
|
||||||
c.metrics.flowsErrors.WithLabelValues(exporterStr, "metadata cache miss").Inc()
|
|
||||||
skip = true
|
|
||||||
} else {
|
|
||||||
flowExporterName = answer.Exporter.Name
|
flowExporterName = answer.Exporter.Name
|
||||||
expClassification.Region = answer.Exporter.Region
|
expClassification.Region = answer.Exporter.Region
|
||||||
expClassification.Role = answer.Exporter.Role
|
expClassification.Role = answer.Exporter.Role
|
||||||
@@ -61,14 +58,7 @@ func (w *worker) enrichFlow(exporterIP netip.Addr, exporterStr string) bool {
|
|||||||
|
|
||||||
if flow.OutIf != 0 {
|
if flow.OutIf != 0 {
|
||||||
answer := c.d.Metadata.Lookup(t, exporterIP, uint(flow.OutIf))
|
answer := c.d.Metadata.Lookup(t, exporterIP, uint(flow.OutIf))
|
||||||
if !answer.Found {
|
if answer.Found {
|
||||||
// Only register a cache miss if we don't have one.
|
|
||||||
// TODO: maybe we could do one SNMP query for both interfaces.
|
|
||||||
if !skip {
|
|
||||||
c.metrics.flowsErrors.WithLabelValues(exporterStr, "metadata cache miss").Inc()
|
|
||||||
skip = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
flowExporterName = answer.Exporter.Name
|
flowExporterName = answer.Exporter.Name
|
||||||
expClassification.Region = answer.Exporter.Region
|
expClassification.Region = answer.Exporter.Region
|
||||||
expClassification.Role = answer.Exporter.Role
|
expClassification.Role = answer.Exporter.Role
|
||||||
@@ -90,6 +80,9 @@ func (w *worker) enrichFlow(exporterIP netip.Addr, exporterStr string) bool {
|
|||||||
if flow.OutIf == 0 && flow.InIf == 0 {
|
if flow.OutIf == 0 && flow.InIf == 0 {
|
||||||
c.metrics.flowsErrors.WithLabelValues(exporterStr, "input and output interfaces missing").Inc()
|
c.metrics.flowsErrors.WithLabelValues(exporterStr, "input and output interfaces missing").Inc()
|
||||||
skip = true
|
skip = true
|
||||||
|
} else if flowExporterName == "" {
|
||||||
|
c.metrics.flowsErrors.WithLabelValues(exporterStr, "metadata cache miss").Inc()
|
||||||
|
skip = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if samplingRate, ok := c.config.OverrideSamplingRate.Lookup(exporterIP); ok && samplingRate > 0 {
|
if samplingRate, ok := c.config.OverrideSamplingRate.Lookup(exporterIP); ok && samplingRate > 0 {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -31,10 +32,11 @@ import (
|
|||||||
|
|
||||||
func TestEnrich(t *testing.T) {
|
func TestEnrich(t *testing.T) {
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
Name string
|
Name string
|
||||||
Configuration gin.H
|
Configuration gin.H
|
||||||
InputFlow func() *schema.FlowMessage
|
InputFlow func() *schema.FlowMessage
|
||||||
OutputFlow *schema.FlowMessage
|
OutputFlow *schema.FlowMessage
|
||||||
|
ExpectedMetrics map[string]string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Name: "no rule",
|
Name: "no rule",
|
||||||
@@ -583,6 +585,38 @@ ClassifyProviderRegex(Interface.Description, "^Transit: ([^ ]+)", "$1")`,
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "flow with missing interfaces",
|
||||||
|
Configuration: gin.H{},
|
||||||
|
InputFlow: func() *schema.FlowMessage {
|
||||||
|
return &schema.FlowMessage{
|
||||||
|
SamplingRate: 1000,
|
||||||
|
ExporterAddress: netip.MustParseAddr("::ffff:192.0.2.142"),
|
||||||
|
InIf: 0,
|
||||||
|
OutIf: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OutputFlow: nil,
|
||||||
|
ExpectedMetrics: map[string]string{
|
||||||
|
`flows_errors_total{error="input and output interfaces missing",exporter="192.0.2.142"}`: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "flow with metadata cache miss",
|
||||||
|
Configuration: gin.H{},
|
||||||
|
InputFlow: func() *schema.FlowMessage {
|
||||||
|
return &schema.FlowMessage{
|
||||||
|
SamplingRate: 1000,
|
||||||
|
ExporterAddress: netip.MustParseAddr("::ffff:192.0.2.142"),
|
||||||
|
InIf: 999,
|
||||||
|
OutIf: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
OutputFlow: nil,
|
||||||
|
ExpectedMetrics: map[string]string{
|
||||||
|
`flows_errors_total{error="metadata cache miss",exporter="192.0.2.142"}`: "1",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
t.Run(tc.Name, func(t *testing.T) {
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
@@ -684,6 +718,7 @@ ClassifyProviderRegex(Interface.Description, "^Transit: ([^ ]+)", "$1")`,
|
|||||||
if tc.OutputFlow != nil {
|
if tc.OutputFlow != nil {
|
||||||
expectedMetrics[`forwarded_flows_total{exporter="192.0.2.142"}`] = "1"
|
expectedMetrics[`forwarded_flows_total{exporter="192.0.2.142"}`] = "1"
|
||||||
}
|
}
|
||||||
|
maps.Copy(expectedMetrics, tc.ExpectedMetrics)
|
||||||
if diff := helpers.Diff(gotMetrics, expectedMetrics); diff != "" {
|
if diff := helpers.Diff(gotMetrics, expectedMetrics); diff != "" {
|
||||||
t.Fatalf("Metrics (-got, +want):\n%s", diff)
|
t.Fatalf("Metrics (-got, +want):\n%s", diff)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user