Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usm: http2: Make TestHTTP2KernelTelemetry generic per HTTP2_TELEMETRY_MAX_PATH_LEN #33851

Merged
merged 4 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions pkg/network/protocols/http2/telemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type kernelTelemetry struct {
// endOfStreamRST Count of RST flags seen
endOfStreamRST *libtelemetry.TLSAwareCounter
// pathSizeBucket Count of path sizes divided into buckets.
pathSizeBucket [http2PathBuckets + 1]*libtelemetry.TLSAwareCounter
pathSizeBucket [PathBucketsCount + 1]*libtelemetry.TLSAwareCounter
// literalValueExceedsFrame Count of times we couldn't retrieve the literal value due to reaching the end of the frame.
literalValueExceedsFrame *libtelemetry.TLSAwareCounter
// exceedingMaxInterestingFrames Count of times we reached the max number of frames per iteration.
Expand Down Expand Up @@ -113,10 +113,10 @@ func (t *HTTP2Telemetry) Sub(other HTTP2Telemetry) *HTTP2Telemetry {
}
}

func computePathSizeBucketDifferences(pathSizeBucket, otherPathSizeBucket [http2PathBuckets + 1]uint64) [http2PathBuckets + 1]uint64 {
var result [http2PathBuckets + 1]uint64
func computePathSizeBucketDifferences(pathSizeBucket, otherPathSizeBucket [PathBucketsCount + 1]uint64) [PathBucketsCount + 1]uint64 {
var result [PathBucketsCount + 1]uint64

for i := 0; i < http2PathBuckets+1; i++ {
for i := 0; i < PathBucketsCount+1; i++ {
result[i] = pathSizeBucket[i] - otherPathSizeBucket[i]
}

Expand Down
6 changes: 4 additions & 2 deletions pkg/network/protocols/http2/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ package http2
import "C"

const (
maxHTTP2Path = C.HTTP2_MAX_PATH_LEN
http2PathBuckets = C.HTTP2_TELEMETRY_PATH_BUCKETS
maxHTTP2Path = C.HTTP2_MAX_PATH_LEN
PathBucketsCount = C.HTTP2_TELEMETRY_PATH_BUCKETS
MaxTelemetryPathLen = C.HTTP2_TELEMETRY_MAX_PATH_LEN
PathBucketSize = C.HTTP2_TELEMETRY_PATH_BUCKETS_SIZE
// The kernel limit per page in the per-cpu array of the http2 terminated connections map.
HTTP2TerminatedBatchSize = C.HTTP2_TERMINATED_BATCH_SIZE
// The upper limit for the size of the raw status code.
Expand Down
6 changes: 4 additions & 2 deletions pkg/network/protocols/http2/types_linux.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 62 additions & 20 deletions pkg/network/usm/usm_http2_monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"errors"
"fmt"
"io"
"math/rand"
"net"
"net/http"
"reflect"
Expand Down Expand Up @@ -334,26 +335,61 @@ func (s *usmHTTP2Suite) TestSimpleHTTP2() {
var (
// pathExceedingMaxSize is path with size 166, which is exceeding the maximum path size in the kernel (HTTP2_MAX_PATH_LEN).
pathExceedingMaxSize = "X2YRUwfeNEmYWkk0bACThVya8MoSUkR7ZKANCPYkIGHvF9CWGA0rxXKsGogQag7HsJfmgaar3TiOTRUb3ynbmiOz3As9rXYjRGNRdCWGgdBPL8nGa6WheGlJLNtIVsUcxSerNQKmoQqqDLjGftbKXjqdMJLVY6UyECeXOKrrFU9aHx2fjlk2qMNDUptYWuzPPCWAnKOV7Ph"
)

// generateRandomString creates a random ASCII string of a given size, ensuring it starts with '/'
func generateRandomString(size int) string {
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
rand.New(rand.NewSource(time.Now().UnixNano()))

http2UniquePaths = []string{
// size 82 bucket 0
"C9ZaSMOpthT9XaRh9yc6AKqfIjT43M8gOz3p9ASKCNRIcLbc3PTqEoms2SDwt6Q90QM7DxjWKlmZUfRU1eOx5DjQOOhLaIJQke4N",
// size 127 bucket 1
"ZtZuUQeVB7BOl3F45oFicOOOJl21ePFwunMBvBh3bXPMBZqdEZepVsemYA0frZb5M83VHLDWq68KFELDHu0Xo28lzpzO3L7kDXuYuClivgEgURUn47kfwfUfW1PKjfsV6HaYpAZxly48lTGiRIXRINVC8b9",
// size 137, bucket 2
"RDBVk5COXAz52GzvuHVWRawNoKhmfxhBiTuyj5QZ6qR1DMsNOn4sWFLnaGXVzrqA8NLr2CaW1IDupzh9AzJlIvgYSf6OYIafIOsImL5O9M3AHzUHGMJ0KhjYGJAzXeTgvwl2qYWmlD9UYGELFpBSzJpykoriocvl3RRoYt4l",
// size 147, bucket 3
"T5r8QcP8qCiKVwhWlaxWjYCX8IrTmPrt2HRjfQJP2PxbWjLm8dP4BTDxUAmXJJWNyv4HIIaR3Fj6n8Tu6vSoDcBtKFuMqIPAdYEJt0qo2aaYDKomIJv74z7SiN96GrOufPTm6Eutl3JGeAKW2b0dZ4VYUsIOO8aheEOGmyhyWBymgCtBcXeki1",
// size 158, bucket 4
"VP4zOrIPiGhLDLSJYSVU78yUcb8CkU0dVDIZqPq98gVoenX5p1zS6cRX4LtrfSYKCQFX6MquluhDD2GPjZYFIraDLIHCno3yipQBLPGcPbPTgv9SD6jOlHMuLjmsGxyC3y2Hk61bWA6Af4D2SYS0q3BS7ahJ0vjddYYBRIpwMOOIez2jaR56rPcGCRW2eq0T1x",
// size 166, bucket 5
pathExceedingMaxSize,
// size 172, bucket 6
"bq5bcpUgiW1CpKgwdRVIulFMkwRenJWYdW8aek69anIV8w3br0pjGNtfnoPCyj4HUMD5MxWB2xM4XGp7fZ1JRHvskRZEgmoM7ag9BeuigmH05p7dzMwKsD76MqKyPmfhwBUZHLKtJ52ia3mOuMvyYiQNwA6KAU509bwuy4NCREVUAP76WFeAzr0jBvqMFXLg3eQQERIW0tKTcjQg8m9Jse",
// size 247, bucket 7
"LUhWUWPMztVFuEs83i7RmoxRiV1KzOq0NsZmGXVyW49BbBaL63m8H5vDwiewrrKbldXBuctplDxB28QekDclM6cO9BIsRqvzS3a802aOkRHTEruotA8Xh5K9GOMv9DzdoOL9P3GFPsUPgBy0mzFyyRJGk3JXpIH290Bj2FIRnIIpIjjKE1akeaimsuGEheA4D95axRpGmz4cm2s74UiksfBi4JnVX2cBzZN3oQaMt7zrWofwyzcZeF5W1n6BAQWxPPWe4Jyoc34jQ2fiEXQO0NnXe1RFbBD1E33a0OycziXZH9hEP23xvh",
if size == 0 {
return "/"
}
)

result := make([]byte, size)
result[0] = '/' // Ensure the first character is '/'

for i := 1; i < size; i++ {
result[i] = charset[rand.Intn(len(charset))]
}
return string(result)
}

// generateHuffmanEncodedString ensures the encoded output is exactly 'length' bytes.
// Since there's no direct way to control the output size of Huffman encoding, we need to guess what input
// string will produce the desired output size.
func generateHuffmanEncodedString(targetLength int) ([]byte, string) {
amitslavin marked this conversation as resolved.
Show resolved Hide resolved
estimate := targetLength
var encoded []byte
var original string

for {
original = generateRandomString(estimate)
amitslavin marked this conversation as resolved.
Show resolved Hide resolved
encoded = hpack.AppendHuffmanString(nil, original)

if len(encoded) == targetLength {
break
} else if len(encoded) > targetLength {
estimate-- // Reduce input size if output is too long
} else {
estimate++ // Increase input size if output is too short
}
}

return encoded, original
}

// TestEncode meant to verify the correctness of generateHuffmanEncodedString function.
func TestEncode(t *testing.T) {
for i := 1; i < 500; i++ {
encoded, original := generateHuffmanEncodedString(i)
require.Len(t, encoded, i)
require.True(t, strings.HasPrefix(original, "/"))
decoded, err := hpack.HuffmanDecodeToString(encoded)
require.NoError(t, err)
assert.Equal(t, original, decoded)
}
}

func (s *usmHTTP2Suite) TestHTTP2KernelTelemetry() {
t := s.T()
Expand Down Expand Up @@ -381,9 +417,15 @@ func (s *usmHTTP2Suite) TestHTTP2KernelTelemetry() {
name: "Fill each bucket",
runClients: func(t *testing.T, clientsCount int) {
clients := getHTTP2UnixClientArray(clientsCount, unixPath)
for _, path := range http2UniquePaths {
lengths := make([]int, usmhttp2.PathBucketsCount+1)
for i := 0; i < len(lengths); i++ {
lengths[i] = usmhttp2.MaxTelemetryPathLen + i*usmhttp2.PathBucketSize
}
for _, length := range lengths {
enc, original := generateHuffmanEncodedString(length)
require.Len(t, enc, length)
client := clients[getClientsIndex(1, clientsCount)]
req, err := client.Post(http2SrvAddr+"/"+path, "application/json", bytes.NewReader([]byte("test")))
req, err := client.Post(http2SrvAddr+original, "application/json", bytes.NewReader([]byte("test")))
require.NoError(t, err, "could not make request")
_ = req.Body.Close()
}
Expand Down
Loading