Skip to content

Commit 95a48c1

Browse files
authored
fix(packetparser): Fix under reporting of TCP flags and packet metrics, improve scalability (#1665)
# Description Previously `packetparser` in `high` `dataAggregationLevel` would report (mostly) every single packet since important flags were observed over the lifetime of the connection. This changes that behavior to only observe the important flags on individual packets and report when necessary. This will mean less packets are reported. However, it also adds back weighting for bytes, packets, and TCP flags so that metrics remain accurate versus before. I also noticed the current docs for the TCP flags metrics are inaccurate, we only report a subset of the supported flags. Not sure if this is intentional, however supporting more flags will put more memory pressure on both conntrack as well as performance pressure on packet reporting. With sampling in place, this should be more than worth it but there may be repercussions for the performance of `low` `dataAggregationLevel`. ## Checklist - [X] I have read the [contributing documentation](https://retina.sh/docs/Contributing/overview). - [X] I signed and signed-off the commits (`git commit -S -s ...`). See [this documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) on signing commits. - [X] I have correctly attributed the author(s) of the code. - [X] I have tested the changes locally. - [X] I have followed the project's style guidelines. - [X] I have updated the documentation, if necessary. - [X] I have added tests, if applicable. ## Screenshots (if applicable) or Testing Completed eBPF objects compile and load as expected. # `main` Branch <img width="1463" alt="tcpflags main" src="https://github.com/user-attachments/assets/167908f0-7c37-4498-a7f6-20a41110d925" /> <img width="1463" alt="prometheus packets retina main" src="https://github.com/user-attachments/assets/de8ad834-ed91-4673-8643-aa9cc51b3451" /> <img width="1463" alt="prometheus bytes retina main" src="https://github.com/user-attachments/assets/420f54dc-fbbe-4a7b-a290-24c5d6666518" /> # This Branch <img width="1463" alt="tcpflags patched" src="https://github.com/user-attachments/assets/88460ee0-f769-4992-b9be-392b38a64b19" /> <img width="1463" alt="prometheus packets retina patched" src="https://github.com/user-attachments/assets/304bbb97-8c57-477f-9c19-91bb1510b9c7" /> <img width="1463" alt="prometheus bytes retina patched" src="https://github.com/user-attachments/assets/ef917562-487e-45be-8fbb-c9573fa708c1" /> ## Additional Notes #1628 will be a follow-up to this to add additional sampling functionality. --- Please refer to the [CONTRIBUTING.md](../CONTRIBUTING.md) file for more information on how to contribute to this project. Signed-off-by: Matthew McKeen <matthew.mckeen@fastly.com>
1 parent ba36848 commit 95a48c1

20 files changed

Lines changed: 1568 additions & 1016 deletions

pkg/metrics/metrics.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,12 @@ func InitializeMetrics() {
188188
ConntrackTotalConnectionsDescription,
189189
)
190190

191+
ParsedPacketsCounter = exporter.CreatePrometheusCounterVecForControlPlaneMetric(
192+
exporter.DefaultRegistry,
193+
parsedPacketsCounterName,
194+
parsedPacketsCounterDescription,
195+
)
196+
191197
isInitialized = true
192198
metricsLogger.Info("Metrics initialized")
193199
}

pkg/metrics/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const (
1212
// Control plane metrics
1313
pluginManagerFailedToReconcileCounterName = "plugin_manager_failed_to_reconcile"
1414
lostEventsCounterName = "lost_events_counter"
15+
parsedPacketsCounterName = "parsed_packets_counter"
1516

1617
// Windows
1718
hnsStats = "windows_hns_stats"
@@ -43,6 +44,7 @@ const (
4344
// Control plane metrics
4445
pluginManagerFailedToReconcileCounterDescription = "Number of times the plugin manager failed to reconcile the plugins"
4546
lostEventsCounterDescription = "Number of events lost in control plane"
47+
parsedPacketsCounterDescription = "Number of packets parsed by the packetparser plugin"
4648

4749
// Conntrack metrics
4850
ConntrackPacketTxDescription = "Number of tx packets"
@@ -90,6 +92,7 @@ var (
9092
// Control Plane Metrics
9193
PluginManagerFailedToReconcileCounter CounterVec
9294
LostEventsCounter CounterVec
95+
ParsedPacketsCounter CounterVec
9396

9497
// DNS Metrics.
9598
DNSRequestCounter CounterVec

pkg/module/metrics/forward.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ func (f *ForwardMetrics) processLocalCtxFlow(flow *v1.Flow) {
170170
func (f *ForwardMetrics) update(fl *v1.Flow, labels []string) {
171171
switch f.metricName {
172172
case utils.ForwardPacketsGaugeName:
173-
f.forwardMetric.WithLabelValues(labels...).Inc()
173+
f.forwardMetric.WithLabelValues(labels...).Add(float64(utils.PreviouslyObservedPackets(fl) + 1))
174174
case utils.ForwardBytesGaugeName:
175-
f.forwardMetric.WithLabelValues(labels...).Add(float64(utils.PacketSize(fl)))
175+
f.forwardMetric.WithLabelValues(labels...).Add(float64(utils.PacketSize(fl) + utils.PreviouslyObservedBytes(fl)))
176176
}
177177
}

pkg/module/metrics/latency_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func TestProcessFlow(t *testing.T) {
124124
f1 := utils.ToFlow(l, t1, apiSeverIp, nodeIp, 80, 443, 6, 3, 0)
125125
metaf1 := &utils.RetinaMetadata{}
126126
utils.AddTCPID(metaf1, 1234)
127-
utils.AddTCPFlags(f1, 1, 0, 0, 0, 0, 0)
127+
utils.AddTCPFlags(f1, 1, 0, 0, 0, 0, 0, 0, 0, 0)
128128
utils.AddRetinaMetadata(f1, metaf1)
129129
f1.Destination = &flow.Endpoint{
130130
PodName: "kubernetes-apiserver",
@@ -134,7 +134,7 @@ func TestProcessFlow(t *testing.T) {
134134
f2 := utils.ToFlow(l, t2, nodeIp, apiSeverIp, 443, 80, 6, 2, 0)
135135
metaf2 := &utils.RetinaMetadata{}
136136
utils.AddTCPID(metaf2, 1234)
137-
utils.AddTCPFlags(f2, 1, 1, 0, 0, 0, 0)
137+
utils.AddTCPFlags(f2, 1, 1, 0, 0, 0, 0, 0, 0, 0)
138138
utils.AddRetinaMetadata(f2, metaf2)
139139
f2.Source = &flow.Endpoint{
140140
PodName: "kubernetes-apiserver",
@@ -147,9 +147,9 @@ func TestProcessFlow(t *testing.T) {
147147
* Test case 2: Existing TCP connection.
148148
*/
149149
// Node -> Api server.
150-
utils.AddTCPFlags(f1, 1, 0, 0, 0, 0, 0)
150+
utils.AddTCPFlags(f1, 1, 0, 0, 0, 0, 0, 0, 0, 0)
151151
// Api server -> Node.
152-
utils.AddTCPFlags(f2, 0, 1, 0, 0, 0, 0)
152+
utils.AddTCPFlags(f2, 0, 1, 0, 0, 0, 0, 0, 0, 0)
153153
// Process flow.
154154
lm.ProcessFlow(f1)
155155
lm.ProcessFlow(f2)

pkg/module/metrics/tcpflags.go

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ func (t *TCPMetrics) getLabels() []string {
6565
return labels
6666
}
6767

68+
func combineFlagsWithPrevious(flags []string, flow *v1.Flow) map[string]uint32 {
69+
var combinedFlags map[string]uint32
70+
71+
previous := utils.PreviouslyObservedTCPFlags(flow)
72+
if previous != nil {
73+
combinedFlags = previous
74+
} else {
75+
combinedFlags = map[string]uint32{}
76+
}
77+
78+
for _, flag := range flags {
79+
if _, ok := combinedFlags[flag]; !ok {
80+
combinedFlags[flag] = 1
81+
} else {
82+
combinedFlags[flag]++
83+
}
84+
}
85+
86+
return combinedFlags
87+
}
88+
6889
func (t *TCPMetrics) ProcessFlow(flow *v1.Flow) {
6990
if flow == nil {
7091
return
@@ -100,11 +121,11 @@ func (t *TCPMetrics) ProcessFlow(flow *v1.Flow) {
100121
dstLabels = t.dstCtx.getValues(flow)
101122
}
102123

103-
for _, flag := range flags {
124+
for flag, count := range combineFlagsWithPrevious(flags, flow) {
104125
labels := append([]string{flag}, srcLabels...)
105126
labels = append(labels, dstLabels...)
106-
t.tcpFlagsMetrics.WithLabelValues(labels...).Inc()
107-
t.l.Debug("TCP flag metric", zap.String("flag", flag), zap.Strings("labels", labels))
127+
t.tcpFlagsMetrics.WithLabelValues(labels...).Add(float64(count))
128+
t.l.Debug("TCP flag metric", zap.String("flag", flag), zap.Strings("labels", labels), zap.Uint32("count", count))
108129
}
109130
}
110131

@@ -113,20 +134,23 @@ func (t *TCPMetrics) processLocalCtxFlow(flow *v1.Flow, flags []string) {
113134
if labelValuesMap == nil {
114135
return
115136
}
137+
138+
combinedFlags := combineFlagsWithPrevious(flags, flow)
139+
116140
// Ingress values
117141
if l := len(labelValuesMap[ingress]); l > 0 {
118-
for _, flag := range flags {
142+
for flag, count := range combinedFlags {
119143
labels := append([]string{flag}, labelValuesMap[ingress]...)
120-
t.tcpFlagsMetrics.WithLabelValues(labels...).Inc()
121-
t.l.Debug("TCP flag metric", zap.String("flag", flag), zap.Strings("labels", labels))
144+
t.tcpFlagsMetrics.WithLabelValues(labels...).Add(float64(count))
145+
t.l.Debug("TCP flag metric", zap.String("flag", flag), zap.Strings("labels", labels), zap.Uint32("count", count))
122146
}
123147
}
124148

125149
if l := len(labelValuesMap[egress]); l > 0 {
126-
for _, flag := range flags {
150+
for flag, count := range combinedFlags {
127151
labels := append([]string{flag}, labelValuesMap[egress]...)
128-
t.tcpFlagsMetrics.WithLabelValues(labels...).Inc()
129-
t.l.Debug("TCP flag metric", zap.String("flag", flag), zap.Strings("labels", labels))
152+
t.tcpFlagsMetrics.WithLabelValues(labels...).Add(float64(count))
153+
t.l.Debug("TCP flag metric", zap.String("flag", flag), zap.Strings("labels", labels), zap.Uint32("count", count))
130154
}
131155
}
132156
}
@@ -171,6 +195,10 @@ func (t *TCPMetrics) getFlagValues(flags *v1.TCPFlags) []string {
171195
f = append(f, utils.CWR)
172196
}
173197

198+
if flags.GetNS() {
199+
f = append(f, utils.NS)
200+
}
201+
174202
return f
175203
}
176204

0 commit comments

Comments
 (0)