Skip to content

Commit 304c944

Browse files
committed
CR comments
1 parent 5948810 commit 304c944

File tree

8 files changed

+50
-32
lines changed

8 files changed

+50
-32
lines changed

pkg/network/ebpf/c/protocols/redis/decoding-maps.h

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// Keeps track of in-flight Redis transactions
1010
BPF_HASH_MAP(redis_in_flight, conn_tuple_t, redis_transaction_t, 0)
1111

12+
// Acts as a scratch buffer for Redis events, for preparing events before they are sent to userspace.
1213
BPF_PERCPU_ARRAY_MAP(redis_scratch_buffer, redis_event_t, 1)
1314

1415
#endif /* __REDIS_MAPS_H */

pkg/network/ebpf/c/protocols/redis/decoding.h

+32-20
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
#include "protocols/redis/decoding-maps.h"
55
#include "protocols/helpers/pktbuf.h"
66

7-
#define BLK_SIZE (16)
8-
PKTBUF_READ_INTO_BUFFER(redis_bulk, MAX_KEY_LEN, BLK_SIZE)
7+
PKTBUF_READ_INTO_BUFFER(redis_bulk, MAX_KEY_LEN, READ_KEY_CHUNK_SIZE)
98

109
// Read a CRLF terminator from the packet buffer. The terminator is expected to be in the format: \r\n.
1110
// The function returns true if the terminator was successfully read, or false if the terminator could not be read.
@@ -49,6 +48,8 @@ static __always_inline u32 read_array_message_param_count(pktbuf_t pkt) {
4948
return param_count - '0';
5049
}
5150

51+
// Extracts and returns the length of a Redis key from a RESP bulk string.
52+
// Validates the format and returns 0 if invalid or exceeds maximum length.
5253
static __always_inline u16 get_key_len(pktbuf_t pkt) {
5354
u32 current_offset = pktbuf_data_offset(pkt);
5455
const u32 data_end = pktbuf_data_end(pkt);
@@ -63,8 +64,8 @@ static __always_inline u16 get_key_len(pktbuf_t pkt) {
6364
}
6465
current_offset++;
6566

66-
// Read key length (up to 3 digits)
67-
char key_size_bytes[3] = {};
67+
// Read key length (up to MAX_DIGITS_KEY_LEN_PREFIX digits)
68+
char key_size_bytes[MAX_DIGITS_KEY_LEN_PREFIX] = {};
6869
if (current_offset + sizeof(key_size_bytes) > data_end) {
6970
return 0;
7071
}
@@ -75,8 +76,8 @@ static __always_inline u16 get_key_len(pktbuf_t pkt) {
7576
u16 key_size = 0;
7677
u32 digits_read = 0;
7778
// The key length is a decimal number, so we need to convert it from ASCII to an integer.
78-
#pragma unroll (3)
79-
for (int i = 0; i < 3; i++) {
79+
#pragma unroll (MAX_DIGITS_KEY_LEN_PREFIX)
80+
for (int i = 0; i < MAX_DIGITS_KEY_LEN_PREFIX; i++) {
8081
if (key_size_bytes[i] == RESP_TERMINATOR_1) {
8182
break;
8283
}
@@ -95,13 +96,15 @@ static __always_inline u16 get_key_len(pktbuf_t pkt) {
9596
return 0;
9697
}
9798

98-
if (key_size <= 0 || key_size > 999) {
99+
if (key_size <= 0 || key_size > MAX_READABLE_KEY_LEN) {
99100
return 0;
100101
}
101102

102103
return key_size;
103104
}
104105

106+
// Reads a Redis key name into the provided buffer with length validation.
107+
// Sets truncated flag if key was too long for buffer, and out_key_len as the key size after clamping.
105108
static __always_inline bool read_key_name(pktbuf_t pkt, char *buf, u8 buf_len, u16 *out_key_len, bool *truncated) {
106109
const u32 key_size = *out_key_len > MAX_KEY_LEN - 1 ? MAX_KEY_LEN - 1 : *out_key_len;
107110
const u32 final_key_size = key_size > buf_len ? buf_len : key_size;
@@ -124,15 +127,16 @@ static __always_inline bool read_key_name(pktbuf_t pkt, char *buf, u8 buf_len, u
124127
return true;
125128
}
126129

127-
// Process a Redis request from the packet buffer. The function reads the request from the packet buffer,
128-
// and returns the method (GET or SET) and the key(up to MAX_KEY_LEN bytes).
130+
131+
// Processes incoming Redis requests (GET or SET commands).
132+
// Extracts command type and key (up to MAX_KEY_LEN bytes), stores transaction info in redis_in_flight map.
129133
static __always_inline void process_redis_request(pktbuf_t pkt, conn_tuple_t *conn_tuple) {
130134
u32 param_count = read_array_message_param_count(pkt);
131135
if (param_count == 0) {
132136
return;
133137
}
134138
// GET message has 2 parameters, SET message has 3-5 parameters. Anything else is irrelevant for us.
135-
if (param_count < 2 || param_count > 5) {
139+
if (param_count < MIN_PARAM_COUNT || param_count > MAX_PARAM_COUNT) {
136140
return;
137141
}
138142

@@ -174,10 +178,12 @@ static __always_inline void process_redis_request(pktbuf_t pkt, conn_tuple_t *co
174178
return;
175179
}
176180

177-
bpf_map_update_elem(&redis_in_flight, conn_tuple, &transaction, BPF_ANY);
181+
bpf_map_update_with_telemetry(redis_in_flight, conn_tuple, &transaction, BPF_ANY);
178182
}
179183

180-
// Handles a TCP termination event by deleting the connection tuple from the in-flight map.
184+
185+
// Handles TCP connection termination by cleaning up in-flight transactions.
186+
// Removes entries from redis_in_flight map for both directions.
181187
static void __always_inline redis_tcp_termination(conn_tuple_t *tup) {
182188
bpf_map_delete_elem(&redis_in_flight, tup);
183189
flip_tuple(tup);
@@ -198,6 +204,8 @@ static __always_inline void redis_batch_enqueue_wrapper(conn_tuple_t *tuple, red
198204
redis_batch_enqueue(event);
199205
}
200206

207+
// Processes Redis response messages and validates their format.
208+
// Handles error responses and command-specific response types.
201209
static void __always_inline process_redis_response(pktbuf_t pkt, conn_tuple_t *tup, redis_transaction_t *transaction) {
202210
char first_byte;
203211
if (pktbuf_load_bytes_from_current_offset(pkt, &first_byte, sizeof(first_byte)) < 0) {
@@ -207,16 +215,12 @@ static void __always_inline process_redis_response(pktbuf_t pkt, conn_tuple_t *t
207215
transaction->is_error = true;
208216
goto enqueue;
209217
}
210-
if (transaction->command == REDIS_GET) {
211-
if (first_byte != RESP_BULK_PREFIX) {
212-
goto cleanup;
213-
}
218+
if (transaction->command == REDIS_GET && first_byte == RESP_BULK_PREFIX) {
214219
goto enqueue;
215-
} else{
216-
if (first_byte != RESP_SIMPLE_STRING_PREFIX) {
217-
goto cleanup;
218-
}
220+
} else if (transaction->command == REDIS_SET && first_byte == RESP_SIMPLE_STRING_PREFIX){
219221
goto enqueue;
222+
} else {
223+
goto cleanup;
220224
}
221225

222226
enqueue:
@@ -226,6 +230,8 @@ static void __always_inline process_redis_response(pktbuf_t pkt, conn_tuple_t *t
226230
bpf_map_delete_elem(&redis_in_flight, tup);
227231
}
228232

233+
// Main socket processing function for Redis traffic.
234+
// Handles both requests and responses based on connection state.
229235
SEC("socket/redis_process")
230236
int socket__redis_process(struct __sk_buff *skb) {
231237
skb_info_t skb_info = {};
@@ -251,6 +257,8 @@ int socket__redis_process(struct __sk_buff *skb) {
251257
return 0;
252258
}
253259

260+
// Processes Redis messages over TLS connections.
261+
// Similar to socket__redis_process but handles TLS-encrypted traffic.
254262
SEC("uprobe/redis_tls_process")
255263
int uprobe__redis_tls_process(struct pt_regs *ctx) {
256264
const __u32 zero = 0;
@@ -262,6 +270,7 @@ int uprobe__redis_tls_process(struct pt_regs *ctx) {
262270

263271
// Copying the tuple to the stack to handle verifier issues on kernel 4.14.
264272
conn_tuple_t tup = args->tup;
273+
normalize_tuple(&tup);
265274

266275
pktbuf_t pkt = pktbuf_from_tls(ctx, args);
267276
redis_transaction_t *transaction = bpf_map_lookup_elem(&redis_in_flight, &tup);
@@ -273,6 +282,8 @@ int uprobe__redis_tls_process(struct pt_regs *ctx) {
273282
return 0;
274283
}
275284

285+
// Handles termination of TLS Redis connections.
286+
// Cleans up connection state for TLS connections.
276287
SEC("uprobe/redis_tls_termination")
277288
int uprobe__redis_tls_termination(struct pt_regs *ctx) {
278289
const __u32 zero = 0;
@@ -284,6 +295,7 @@ int uprobe__redis_tls_termination(struct pt_regs *ctx) {
284295

285296
// Copying the tuple to the stack to handle verifier issues on kernel 4.14.
286297
conn_tuple_t tup = args->tup;
298+
normalize_tuple(&tup);
287299
redis_tcp_termination(&tup);
288300

289301
return 0;

pkg/network/ebpf/c/protocols/redis/defs.h

+9-4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@
55

66
#define REDIS_CMD_GET "GET"
77
#define REDIS_CMD_SET "SET"
8-
#define MAX_KEY_LEN 128
98
#define RESP_ARRAY_PREFIX '*'
109
#define RESP_BULK_PREFIX '$'
10+
#define RESP_SIMPLE_STRING_PREFIX '+'
1111
#define RESP_ERROR_PREFIX '-'
12+
#define RESP_FIELD_TERMINATOR_LEN 2 // CRLF terminator: \r\n
13+
#define METHOD_LEN 3 // We only support GET and SET for now, both with length 3.
14+
#define MAX_DIGITS_KEY_LEN_PREFIX 3 // Since we clamp key length to 128, when reading key length prefix, we only need to read up to 3 digits.
15+
#define MAX_KEY_LEN 128
16+
#define MIN_PARAM_COUNT 2 // GET command has 2 parameters
17+
#define MAX_PARAM_COUNT 5 // SET command has 3-5 parameters
18+
#define MAX_READABLE_KEY_LEN 999 // Since we read up to 3 digits of key length, the maximum readable length is 999.
19+
#define READ_KEY_CHUNK_SIZE 16 // Read keys in chunks of length 16
1220
#define RESP_TERMINATOR_1 '\r'
1321
#define RESP_TERMINATOR_2 '\n'
14-
#define METHOD_LEN 3
15-
#define RESP_FIELD_TERMINATOR_LEN 2
16-
#define RESP_SIMPLE_STRING_PREFIX '+'
1722
#endif

pkg/network/protocols/redis/debugging/debugging.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
package debugging
88

99
import (
10+
model "github.com/DataDog/agent-payload/v5/process"
11+
1012
"github.com/DataDog/datadog-agent/pkg/network/protocols"
1113
"github.com/DataDog/datadog-agent/pkg/network/protocols/redis"
1214
"github.com/DataDog/datadog-agent/pkg/process/util"
13-
14-
model "github.com/DataDog/agent-payload/v5/process"
1515
)
1616

1717
// address represents represents a IP:Port

pkg/network/protocols/redis/stats.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ package redis
88
import (
99
"errors"
1010

11-
"github.com/DataDog/datadog-agent/pkg/network/protocols"
12-
"github.com/DataDog/datadog-agent/pkg/process/util"
13-
1411
"github.com/DataDog/sketches-go/ddsketch"
1512

13+
"github.com/DataDog/datadog-agent/pkg/network/protocols"
1614
"github.com/DataDog/datadog-agent/pkg/network/types"
15+
"github.com/DataDog/datadog-agent/pkg/process/util"
1716
"github.com/DataDog/datadog-agent/pkg/util/log"
1817
)
1918

@@ -89,6 +88,7 @@ func (r *RequestStats) CombineWith(newStats *RequestStats) {
8988
}
9089
}
9190

91+
// mergeRequests adds a RequestStat to the given RequestStats. Only called when newStats has Latencies.
9292
func (r *RequestStats) mergeRequests(isErr bool, newStats *RequestStat) {
9393
stats, exists := r.ErrorToStats[isErr]
9494
if !exists {

pkg/network/protocols/redis/stats_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Unless explicitly stated otherwise all files in this repository are licensed
22
// under the Apache License Version 2.0.
33
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4-
// Copyright 2016-present Datadog, Inc.
4+
// Copyright 2025-present Datadog, Inc.
55

66
//go:build linux_bpf
77

pkg/network/protocols/redis/statskeeper.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Unless explicitly stated otherwise all files in this repository are licensed
22
// under the Apache License Version 2.0.
33
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4-
// Copyright 2016-present Datadog, Inc.
4+
// Copyright 2025-present Datadog, Inc.
55

66
//go:build linux_bpf
77

pkg/network/protocols/redis/statskeeper_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Unless explicitly stated otherwise all files in this repository are licensed
22
// under the Apache License Version 2.0.
33
// This product includes software developed at Datadog (https://www.datadoghq.com/).
4-
// Copyright 2016-present Datadog, Inc.
4+
// Copyright 2025-present Datadog, Inc.
55

66
//go:build linux_bpf
77

0 commit comments

Comments
 (0)