Skip to content

Commit 404e93f

Browse files
authored
Add HTTP2 protocol identify (#51)
1 parent b034d7d commit 404e93f

File tree

10 files changed

+417
-6
lines changed

10 files changed

+417
-6
lines changed

.github/workflows/rover.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ jobs:
163163
config: test/e2e/cases/profiling/network/c_plus_plus/e2e.yaml
164164
- name: Nodejs Profiling
165165
config: test/e2e/cases/profiling/network/nodejs/e2e.yaml
166+
- name: HTTP2 Profiling
167+
config: test/e2e/cases/profiling/network/http2/e2e.yaml
166168
steps:
167169
- uses: actions/checkout@v2
168170
with:

bpf/profiling/network/protocol_analyze.h

+81
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,85 @@ static __inline __u32 infer_http_message(const char* buf, size_t count) {
111111
return kUnknown;
112112
}
113113

114+
// frame format: https://www.rfc-editor.org/rfc/rfc7540.html#section-4.1
115+
static __inline __u32 infer_http2_message(const char* buf_src, size_t count) {
116+
static const uint8_t kFrameBasicSize = 0x9; // including Length, Type, Flags, Reserved, Stream Identity
117+
static const uint8_t kFrameTypeHeader = 0x1; // the type of the frame: https://www.rfc-editor.org/rfc/rfc7540.html#section-6.2
118+
static const uint8_t kFrameLoopCount = 5;
119+
120+
static const uint8_t kStaticTableMaxSize = 61;// https://www.rfc-editor.org/rfc/rfc7541#appendix-A
121+
static const uint8_t kStaticTableAuth = 1;
122+
static const uint8_t kStaticTableGet = 2;
123+
static const uint8_t kStaticTablePost = 3;
124+
static const uint8_t kStaticTablePath1 = 4;
125+
static const uint8_t kStaticTablePath2 = 5;
126+
127+
// the buffer size must bigger than basic frame size
128+
if (count < kFrameBasicSize) {
129+
return kUnknown;
130+
}
131+
132+
// frame info
133+
__u8 frame[21] = { 0 };
134+
__u32 frameOffset = 0;
135+
// header info
136+
__u8 staticInx, headerBlockFragmentOffset;
137+
138+
// each all frame
139+
#pragma unroll
140+
for (__u8 i = 0; i < kFrameLoopCount; i++) {
141+
if (frameOffset >= count) {
142+
break;
143+
}
144+
145+
// read frame
146+
bpf_probe_read(frame, sizeof(frame), buf_src + frameOffset);
147+
frameOffset += (bpf_ntohl(*(__u32 *) frame) >> 8) + kFrameBasicSize;
148+
149+
// is header frame
150+
if (frame[3] != kFrameTypeHeader) {
151+
continue;
152+
}
153+
154+
// validate the header(unset): not HTTP2 protocol
155+
// this frame must is a send request
156+
if ((frame[4] & 0xd2) || frame[5] & 0x01) {
157+
return kUnknown;
158+
}
159+
160+
// locate the header block fragment offset
161+
headerBlockFragmentOffset = kFrameBasicSize;
162+
if (frame[4] & 0x20) { // PADDED flag is set
163+
headerBlockFragmentOffset += 1;
164+
}
165+
if (frame[4] & 0x20) { // PRIORITY flag is set
166+
headerBlockFragmentOffset += 5;
167+
}
168+
169+
#pragma unroll
170+
for (__u8 j = 0; j <= kStaticTablePath2; j++) {
171+
if (headerBlockFragmentOffset > count) {
172+
return kUnknown;
173+
}
174+
staticInx = frame[headerBlockFragmentOffset] & 0x7f;
175+
if (staticInx <= kStaticTableMaxSize && staticInx > 0) {
176+
if (staticInx == kStaticTableAuth ||
177+
staticInx == kStaticTableGet ||
178+
staticInx == kStaticTablePost ||
179+
staticInx == kStaticTablePath1 ||
180+
staticInx == kStaticTablePath2) {
181+
return kRequest;
182+
} else {
183+
return kResponse;
184+
}
185+
}
186+
headerBlockFragmentOffset++;
187+
}
188+
}
189+
190+
return kUnknown;
191+
}
192+
114193
// Cassandra frame:
115194
// 0 8 16 24 32 40
116195
// +---------+---------+---------+---------+---------+
@@ -678,6 +757,8 @@ static __inline enum message_type_t analyze_protocol(char *buf, __u32 count, str
678757
// PROTOCOL_LIST: Requires update on new protocols.
679758
if ((inferred_message.type = infer_http_message(buf, count)) != kUnknown) {
680759
inferred_message.protocol = kProtocolHTTP;
760+
} else if ((inferred_message.type = infer_http2_message(buf, count)) != kUnknown) {
761+
inferred_message.protocol = kProtocolHTTP2;
681762
} else if ((inferred_message.type = infer_cql_message(buf, count)) != kUnknown) {
682763
inferred_message.protocol = kProtocolCQL;
683764
} else if ((inferred_message.type = infer_mongo_message(buf, count)) != kUnknown) {

docs/en/setup/configuration/profiling.md

+7-6
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ Off CPU Profiling task is attach the `finish_task_switch` in `krobe` to profilin
3232
Network Profiling task is intercept IO-related syscall and `urprobe` in process to identify the network traffic and generate the metrics.
3333
Also, the following protocol are supported for analyzing using OpenSSL library, BoringSSL library, GoTLS, NodeTLS or plaintext:
3434

35-
1. HTTP
36-
2. MySQL
37-
3. CQL(The Cassandra Query Language)
38-
4. MongoDB
39-
5. Kafka
40-
6. DNS
35+
1. HTTP/1.x
36+
2. HTTP/2
37+
3. MySQL
38+
4. CQL(The Cassandra Query Language)
39+
5. MongoDB
40+
6. Kafka
41+
7. DNS
4142

4243
#### Metrics
4344

test/e2e/cases/profiling/network/base/nginx.conf

+14
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,18 @@ http {
3232
proxy_http_version 1.1;
3333
}
3434
}
35+
36+
server {
37+
listen 9000 ssl http2;
38+
server_name proxy;
39+
include mime.types;
40+
default_type application/octet-stream;
41+
42+
ssl_certificate /ssl_data/proxy.crt;
43+
ssl_certificate_key /ssl_data/proxy.key;
44+
45+
location / {
46+
grpc_pass grpcs://service:9000;
47+
}
48+
}
3549
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
FROM golang:1.17
18+
19+
COPY http2/ /service
20+
21+
WORKDIR /
22+
RUN apt update && apt install -y zip && \
23+
mkdir protoc && cd protoc && \
24+
curl -sL https://github.com/protocolbuffers/protobuf/releases/download/v21.5/protoc-21.5-linux-x86_64.zip -o protoc.zip && \
25+
unzip protoc.zip
26+
27+
WORKDIR /service
28+
29+
RUN go get -u google.golang.org/protobuf/cmd/[email protected] && \
30+
go get -u google.golang.org/grpc/cmd/[email protected] && \
31+
go get google.golang.org/grpc/internal/[email protected] && \
32+
/protoc/bin/protoc --go_out=. --go-grpc_out=. service.proto && \
33+
go build .
34+
35+
COPY base/ssl /usr/local/share/ca-certificates
36+
RUN update-ca-certificates
37+
38+
CMD ["/service/test"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
version: '2.1'
17+
18+
services:
19+
service:
20+
build:
21+
context: ../
22+
dockerfile: http2/Dockerfile
23+
volumes:
24+
- ./../base/ssl:/ssl_data
25+
networks:
26+
- e2e
27+
ports:
28+
- 8080:8080
29+
healthcheck:
30+
test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/8080" ]
31+
interval: 5s
32+
timeout: 60s
33+
retries: 120
34+
35+
proxy:
36+
extends:
37+
file: ../base/docker-compose.yml
38+
service: proxy
39+
networks:
40+
- e2e
41+
depends_on:
42+
service:
43+
condition: service_healthy
44+
45+
oap:
46+
extends:
47+
file: ../base/docker-compose.yml
48+
service: oap
49+
ports:
50+
- 12800:12800
51+
52+
rover:
53+
extends:
54+
file: ../base/docker-compose.yml
55+
service: rover
56+
environment:
57+
ROVER_PROCESS_DISCOVERY_REGEX_SCANNER_MATCH_CMD2: service/test
58+
ROVER_PROCESS_DISCOVERY_REGEX_SCANNER_PROCESS_NAME2: service
59+
depends_on:
60+
oap:
61+
condition: service_healthy
62+
63+
networks:
64+
e2e:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
setup:
17+
env: compose
18+
file: docker-compose.yml
19+
timeout: 20m
20+
init-system-environment: ../../../../base/env
21+
steps:
22+
- name: set PATH
23+
command: export PATH=/tmp/skywalking-infra-e2e/bin:$PATH
24+
- name: install yq
25+
command: bash test/e2e/base/scripts/prepare/setup-e2e-shell/install.sh yq
26+
- name: install swctl
27+
command: bash test/e2e/base/scripts/prepare/setup-e2e-shell/install.sh swctl
28+
29+
trigger:
30+
action: http
31+
interval: 3s
32+
times: 10
33+
url: http://${service_host}:${service_8080}/singleCall
34+
method: GET
35+
36+
verify:
37+
# verify with retry strategy
38+
retry:
39+
# max retry count
40+
count: 20
41+
# the interval between two retries, in millisecond.
42+
interval: 10s
43+
cases:
44+
- includes:
45+
- ../network-cases.yaml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Licensed to Apache Software Foundation (ASF) under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Apache Software Foundation (ASF) licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
module test
19+
20+
go 1.17
21+
22+
require (
23+
google.golang.org/grpc v1.44.0
24+
google.golang.org/protobuf v1.25.0
25+
)
26+
27+
require (
28+
github.com/golang/protobuf v1.4.3 // indirect
29+
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
30+
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
31+
golang.org/x/text v0.3.0 // indirect
32+
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
33+
)

0 commit comments

Comments
 (0)