|
|
@@ -9,12 +9,34 @@
|
|
|
#define PROTOCOL_CASSANDRA 8
|
|
|
#define PROTOCOL_RABBITMQ 9
|
|
|
#define PROTOCOL_NATS 10
|
|
|
-
|
|
|
-#define METHOD_UNKNOWN 0
|
|
|
-#define METHOD_PRODUCE 1
|
|
|
-#define METHOD_CONSUME 2
|
|
|
-#define METHOD_STATEMENT_PREPARE 3
|
|
|
-#define METHOD_STATEMENT_CLOSE 4
|
|
|
+#define PROTOCOL_HTTP2 11
|
|
|
+
|
|
|
+#define STATUS_UNKNOWN 0
|
|
|
+#define STATUS_OK 200
|
|
|
+#define STATUS_FAILED 500
|
|
|
+
|
|
|
+#define METHOD_UNKNOWN 0
|
|
|
+#define METHOD_PRODUCE 1
|
|
|
+#define METHOD_CONSUME 2
|
|
|
+#define METHOD_STATEMENT_PREPARE 3
|
|
|
+#define METHOD_STATEMENT_CLOSE 4
|
|
|
+#define METHOD_HTTP2_CLIENT_FRAMES 5
|
|
|
+#define METHOD_HTTP2_SERVER_FRAMES 6
|
|
|
+
|
|
|
+#define MAX_PAYLOAD_SIZE 1024 // must be power of 2
|
|
|
+#define TRUNCATE_PAYLOAD_SIZE(size) ({ \
|
|
|
+ size = MIN(size, MAX_PAYLOAD_SIZE-1); \
|
|
|
+ asm volatile ("%0 &= %1" : "+r"(size) : "i"(MAX_PAYLOAD_SIZE-1)); \
|
|
|
+})
|
|
|
+#define COPY_PAYLOAD(dst, size, src) ({ \
|
|
|
+ TRUNCATE_PAYLOAD_SIZE(size); \
|
|
|
+ if (bpf_probe_read(dst, size, src)) { \
|
|
|
+ return 0; \
|
|
|
+ } \
|
|
|
+})
|
|
|
+
|
|
|
+#define IOVEC_BUF_SIZE MAX_PAYLOAD_SIZE * 2 // must be double of MAX_PAYLOAD_SIZE
|
|
|
+#define MAX_IOVEC_SIZE 32
|
|
|
|
|
|
#include "http.c"
|
|
|
#include "postgres.c"
|
|
|
@@ -26,8 +48,7 @@
|
|
|
#include "cassandra.c"
|
|
|
#include "rabbitmq.c"
|
|
|
#include "nats.c"
|
|
|
-
|
|
|
-#define MAX_PAYLOAD_SIZE 512
|
|
|
+#include "http2.c"
|
|
|
|
|
|
struct l7_event {
|
|
|
__u64 fd;
|
|
|
@@ -39,12 +60,13 @@ struct l7_event {
|
|
|
__u8 method;
|
|
|
__u16 padding;
|
|
|
__u32 statement_id;
|
|
|
+ __u64 payload_size;
|
|
|
char payload[MAX_PAYLOAD_SIZE];
|
|
|
};
|
|
|
|
|
|
struct {
|
|
|
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
|
|
- __type(key, __u32);
|
|
|
+ __type(key, int);
|
|
|
__type(value, struct l7_event);
|
|
|
__uint(max_entries, 1);
|
|
|
} l7_event_heap SEC(".maps");
|
|
|
@@ -59,6 +81,7 @@ struct read_args {
|
|
|
__u64 fd;
|
|
|
char* buf;
|
|
|
__u64* ret;
|
|
|
+ __u64 iovlen;
|
|
|
};
|
|
|
|
|
|
struct {
|
|
|
@@ -68,7 +91,7 @@ struct {
|
|
|
__uint(max_entries, 10240);
|
|
|
} active_reads SEC(".maps");
|
|
|
|
|
|
-struct socket_key {
|
|
|
+struct l7_request_key {
|
|
|
__u64 fd;
|
|
|
__u32 pid;
|
|
|
__u16 is_tls;
|
|
|
@@ -81,23 +104,31 @@ struct l7_request {
|
|
|
__u8 partial;
|
|
|
__u8 request_type;
|
|
|
__s32 request_id;
|
|
|
+ __u64 payload_size;
|
|
|
char payload[MAX_PAYLOAD_SIZE];
|
|
|
};
|
|
|
|
|
|
struct {
|
|
|
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
|
|
- __type(key, __u32);
|
|
|
+ __type(key, int);
|
|
|
__type(value, struct l7_request);
|
|
|
__uint(max_entries, 1);
|
|
|
} l7_request_heap SEC(".maps");
|
|
|
|
|
|
struct {
|
|
|
__uint(type, BPF_MAP_TYPE_LRU_HASH);
|
|
|
- __uint(key_size, sizeof(struct socket_key));
|
|
|
+ __uint(key_size, sizeof(struct l7_request_key));
|
|
|
__uint(value_size, sizeof(struct l7_request));
|
|
|
__uint(max_entries, 32768);
|
|
|
} active_l7_requests SEC(".maps");
|
|
|
|
|
|
+struct {
|
|
|
+ __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
|
|
|
+ __type(key, int);
|
|
|
+ __type(value, char[IOVEC_BUF_SIZE]);
|
|
|
+ __uint(max_entries, 1);
|
|
|
+} iovec_buf_heap SEC(".maps");
|
|
|
+
|
|
|
struct trace_event_raw_sys_enter_rw__stub {
|
|
|
__u64 unused;
|
|
|
long int id;
|
|
|
@@ -117,6 +148,13 @@ struct iovec {
|
|
|
__u64 size;
|
|
|
};
|
|
|
|
|
|
+struct user_msghdr {
|
|
|
+ void *msg_name;
|
|
|
+ int msg_namelen;
|
|
|
+ struct iovec *msg_iov;
|
|
|
+ __u64 msg_iovlen;
|
|
|
+};
|
|
|
+
|
|
|
static inline __attribute__((__always_inline__))
|
|
|
__u64 get_connection_timestamp(__u32 pid, __u64 fd) {
|
|
|
struct sk_info sk = {};
|
|
|
@@ -130,9 +168,53 @@ __u64 get_connection_timestamp(__u32 pid, __u64 fd) {
|
|
|
}
|
|
|
|
|
|
static inline __attribute__((__always_inline__))
|
|
|
-int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size) {
|
|
|
+__u64 read_iovec(char *iovec, __u64 iovlen, __u64 ret, char *buf) {
|
|
|
+ struct iovec iov = {};
|
|
|
+ __u64 max = (ret) ? MIN(ret, MAX_PAYLOAD_SIZE) : MAX_PAYLOAD_SIZE;
|
|
|
+ __u64 offset = 0;
|
|
|
+ __u64 size = 0;
|
|
|
+ #pragma unroll
|
|
|
+ for (int i = 0; i < MAX_IOVEC_SIZE; i++) {
|
|
|
+ if (i >= iovlen) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (bpf_probe_read(&iov, sizeof(iov), (void *)(iovec+i*sizeof(iov)))) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (iov.size <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ size = MIN(iov.size, max-offset);
|
|
|
+ TRUNCATE_PAYLOAD_SIZE(size);
|
|
|
+ TRUNCATE_PAYLOAD_SIZE(offset);
|
|
|
+ if (bpf_probe_read(buf + offset, size, (void *)iov.buf)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ offset += size;
|
|
|
+ if (offset >= max) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return offset;
|
|
|
+}
|
|
|
+
|
|
|
+static inline __attribute__((__always_inline__))
|
|
|
+int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size, __u64 iovlen) {
|
|
|
__u64 id = bpf_get_current_pid_tgid();
|
|
|
- int zero = 0;
|
|
|
+ __u32 zero = 0;
|
|
|
+
|
|
|
+ char* payload = buf;
|
|
|
+ if (iovlen) {
|
|
|
+ payload = bpf_map_lookup_elem(&iovec_buf_heap, &zero);
|
|
|
+ if (!payload) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ size = read_iovec(buf, iovlen, 0, payload);
|
|
|
+ }
|
|
|
+ if (!size) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
struct l7_request *req = bpf_map_lookup_elem(&l7_request_heap, &zero);
|
|
|
if (!req) {
|
|
|
return 0;
|
|
|
@@ -141,15 +223,16 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size)
|
|
|
req->partial = 0;
|
|
|
req->request_id = 0;
|
|
|
req->ns = 0;
|
|
|
- struct socket_key k = {};
|
|
|
+ req->payload_size = size;
|
|
|
+ struct l7_request_key k = {};
|
|
|
k.pid = id >> 32;
|
|
|
k.fd = fd;
|
|
|
k.is_tls = is_tls;
|
|
|
k.stream_id = -1;
|
|
|
|
|
|
- if (is_http_request(buf)) {
|
|
|
+ if (is_http_request(payload)) {
|
|
|
req->protocol = PROTOCOL_HTTP;
|
|
|
- } else if (is_postgres_query(buf, size, &req->request_type)) {
|
|
|
+ } else if (is_postgres_query(payload, size, &req->request_type)) {
|
|
|
if (req->request_type == POSTGRES_FRAME_CLOSE) {
|
|
|
struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
|
|
|
if (!e) {
|
|
|
@@ -159,18 +242,18 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size)
|
|
|
e->fd = k.fd;
|
|
|
e->pid = k.pid;
|
|
|
e->method = METHOD_STATEMENT_CLOSE;
|
|
|
- e->status = 200;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
- bpf_probe_read(e->payload, MAX_PAYLOAD_SIZE, (void *)buf);
|
|
|
+ e->payload_size = size;
|
|
|
+ COPY_PAYLOAD(e->payload, size, payload);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
}
|
|
|
req->protocol = PROTOCOL_POSTGRES;
|
|
|
- } else if (is_redis_query(buf)) {
|
|
|
+ } else if (is_redis_query(payload, size)) {
|
|
|
req->protocol = PROTOCOL_REDIS;
|
|
|
- } else if (is_memcached_query(buf, size)) {
|
|
|
+ } else if (is_memcached_query(payload, size)) {
|
|
|
req->protocol = PROTOCOL_MEMCACHED;
|
|
|
- } else if (is_mysql_query(buf, size, &req->request_type)) {
|
|
|
+ } else if (is_mysql_query(payload, size, &req->request_type)) {
|
|
|
if (req->request_type == MYSQL_COM_STMT_CLOSE) {
|
|
|
struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
|
|
|
if (!e) {
|
|
|
@@ -180,16 +263,16 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size)
|
|
|
e->fd = k.fd;
|
|
|
e->pid = k.pid;
|
|
|
e->method = METHOD_STATEMENT_CLOSE;
|
|
|
- e->status = 200;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
- bpf_probe_read(e->payload, MAX_PAYLOAD_SIZE, (void *)buf);
|
|
|
+ e->payload_size = size;
|
|
|
+ COPY_PAYLOAD(e->payload, size, payload);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
}
|
|
|
req->protocol = PROTOCOL_MYSQL;
|
|
|
- } else if (is_mongo_query(buf, size)) {
|
|
|
+ } else if (is_mongo_query(payload, size)) {
|
|
|
req->protocol = PROTOCOL_MONGO;
|
|
|
- } else if (is_rabbitmq_produce(buf, size)) {
|
|
|
+ } else if (is_rabbitmq_produce(payload, size)) {
|
|
|
struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
|
|
|
if (!e) {
|
|
|
return 0;
|
|
|
@@ -197,12 +280,11 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size)
|
|
|
e->protocol = PROTOCOL_RABBITMQ;
|
|
|
e->fd = k.fd;
|
|
|
e->pid = k.pid;
|
|
|
- e->status = 200;
|
|
|
e->method = METHOD_PRODUCE;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
- } else if (nats_method(buf, size) == METHOD_PRODUCE) {
|
|
|
+ } else if (nats_method(payload, size) == METHOD_PRODUCE) {
|
|
|
struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
|
|
|
if (!e) {
|
|
|
return 0;
|
|
|
@@ -210,45 +292,53 @@ int trace_enter_write(void *ctx, __u64 fd, __u16 is_tls, char *buf, __u64 size)
|
|
|
e->protocol = PROTOCOL_NATS;
|
|
|
e->fd = k.fd;
|
|
|
e->pid = k.pid;
|
|
|
- e->status = 200;
|
|
|
e->method = METHOD_PRODUCE;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
- } else {
|
|
|
- __s32 request_id = is_kafka_request(buf, size);
|
|
|
- if (request_id > 0) {
|
|
|
- req->request_id = request_id;
|
|
|
- req->protocol = PROTOCOL_KAFKA;
|
|
|
- struct l7_request *prev_req = bpf_map_lookup_elem(&active_l7_requests, &k);
|
|
|
- if (prev_req && prev_req->protocol == PROTOCOL_KAFKA) {
|
|
|
- req->ns = prev_req->ns;
|
|
|
- }
|
|
|
- } else {
|
|
|
- __s16 stream_id = is_cassandra_request(buf, size);
|
|
|
- if (stream_id != -1) {
|
|
|
- k.stream_id = stream_id;
|
|
|
- req->protocol = PROTOCOL_CASSANDRA;
|
|
|
- }
|
|
|
+ } else if (is_cassandra_request(payload, size, &k.stream_id)) {
|
|
|
+ req->protocol = PROTOCOL_CASSANDRA;
|
|
|
+ } else if (is_kafka_request(payload, size, &req->request_id)) {
|
|
|
+ req->protocol = PROTOCOL_KAFKA;
|
|
|
+ struct l7_request *prev_req = bpf_map_lookup_elem(&active_l7_requests, &k);
|
|
|
+ if (prev_req && prev_req->protocol == PROTOCOL_KAFKA) {
|
|
|
+ req->ns = prev_req->ns;
|
|
|
}
|
|
|
+ } else if (looks_like_http2_frame(payload, size, METHOD_HTTP2_CLIENT_FRAMES)) {
|
|
|
+ struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
|
|
|
+ if (!e) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ e->protocol = PROTOCOL_HTTP2;
|
|
|
+ e->fd = k.fd;
|
|
|
+ e->pid = k.pid;
|
|
|
+ e->method = METHOD_HTTP2_CLIENT_FRAMES;
|
|
|
+ e->duration = bpf_ktime_get_ns();
|
|
|
+ e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
+ e->payload_size = size;
|
|
|
+ COPY_PAYLOAD(e->payload, size, payload);
|
|
|
+ bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
+ return 0;
|
|
|
}
|
|
|
+
|
|
|
if (req->protocol == PROTOCOL_UNKNOWN) {
|
|
|
return 0;
|
|
|
}
|
|
|
if (req->ns == 0) {
|
|
|
req->ns = bpf_ktime_get_ns();
|
|
|
}
|
|
|
- bpf_probe_read(req->payload, MAX_PAYLOAD_SIZE, (void *)buf);
|
|
|
- bpf_map_update_elem(&active_l7_requests, &k, req, BPF_ANY);
|
|
|
+ COPY_PAYLOAD(req->payload, size, payload);
|
|
|
+ bpf_map_update_elem(&active_l7_requests, &k, req, BPF_NOEXIST);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static inline __attribute__((__always_inline__))
|
|
|
-int trace_enter_read(__u64 id, __u64 fd, char *buf, __u64 *ret) {
|
|
|
+int trace_enter_read(__u64 id, __u64 fd, char *buf, __u64 *ret, __u64 iovlen) {
|
|
|
struct read_args args = {};
|
|
|
args.fd = fd;
|
|
|
args.buf = buf;
|
|
|
args.ret = ret;
|
|
|
+ args.iovlen = iovlen;
|
|
|
bpf_map_update_elem(&active_reads, &id, &args, BPF_ANY);
|
|
|
return 0;
|
|
|
}
|
|
|
@@ -259,7 +349,8 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
|
|
|
if (!args) {
|
|
|
return 0;
|
|
|
}
|
|
|
- struct socket_key k = {};
|
|
|
+
|
|
|
+ struct l7_request_key k = {};
|
|
|
k.pid = pid;
|
|
|
k.fd = args->fd;
|
|
|
k.is_tls = is_tls;
|
|
|
@@ -280,139 +371,168 @@ int trace_exit_read(void *ctx, __u64 id, __u32 pid, __u16 is_tls, long int ret)
|
|
|
}
|
|
|
|
|
|
int zero = 0;
|
|
|
+ char* payload = args->buf;
|
|
|
+ if (args->iovlen) {
|
|
|
+ payload = bpf_map_lookup_elem(&iovec_buf_heap, &zero);
|
|
|
+ if (!payload) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ ret = read_iovec(args->buf, args->iovlen, ret, payload);
|
|
|
+ if (!ret) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
struct l7_event *e = bpf_map_lookup_elem(&l7_event_heap, &zero);
|
|
|
if (!e) {
|
|
|
return 0;
|
|
|
}
|
|
|
e->fd = k.fd;
|
|
|
e->pid = k.pid;
|
|
|
+ e->protocol = PROTOCOL_UNKNOWN;
|
|
|
e->connection_timestamp = 0;
|
|
|
- e->status = 0;
|
|
|
+ e->status = STATUS_UNKNOWN;
|
|
|
e->method = METHOD_UNKNOWN;
|
|
|
e->statement_id = 0;
|
|
|
+ e->payload_size = 0;
|
|
|
|
|
|
- if (is_rabbitmq_consume(args->buf, ret)) {
|
|
|
+ if (is_rabbitmq_consume(payload, ret)) {
|
|
|
e->protocol = PROTOCOL_RABBITMQ;
|
|
|
- e->status = 200;
|
|
|
e->method = METHOD_CONSUME;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
}
|
|
|
- if (nats_method(args->buf, ret) == METHOD_CONSUME) {
|
|
|
+ if (nats_method(payload, ret) == METHOD_CONSUME) {
|
|
|
e->protocol = PROTOCOL_NATS;
|
|
|
- e->status = 200;
|
|
|
e->method = METHOD_CONSUME;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- struct cassandra_header cassandra_response = {};
|
|
|
- cassandra_response.stream_id = -1;
|
|
|
struct l7_request *req = bpf_map_lookup_elem(&active_l7_requests, &k);
|
|
|
+ int response = 0;
|
|
|
if (!req) {
|
|
|
- if (bpf_probe_read(&cassandra_response, sizeof(cassandra_response), (void *)(args->buf)) < 0) {
|
|
|
+ if (is_cassandra_response(payload, ret, &k.stream_id, &e->status)) {
|
|
|
+ req = bpf_map_lookup_elem(&active_l7_requests, &k);
|
|
|
+ if (!req) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ response = 1;
|
|
|
+ } else if (looks_like_http2_frame(payload, ret, METHOD_HTTP2_SERVER_FRAMES)) {
|
|
|
+ e->protocol = PROTOCOL_HTTP2;
|
|
|
+ e->method = METHOD_HTTP2_SERVER_FRAMES;
|
|
|
+ e->duration = bpf_ktime_get_ns();
|
|
|
+ e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
+ e->payload_size = ret;
|
|
|
+ COPY_PAYLOAD(e->payload, ret, payload);
|
|
|
+ bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
- }
|
|
|
- k.stream_id = cassandra_response.stream_id;
|
|
|
- req = bpf_map_lookup_elem(&active_l7_requests, &k);
|
|
|
- if (!req) {
|
|
|
+ } else {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- bpf_probe_read(e->payload, MAX_PAYLOAD_SIZE, req->payload);
|
|
|
- __s32 request_id = req->request_id;
|
|
|
e->protocol = req->protocol;
|
|
|
- __u64 ns = req->ns;
|
|
|
- __u8 partial = req->partial;
|
|
|
- __u8 request_type = req->request_type;
|
|
|
+ e->payload_size = req->payload_size;
|
|
|
+ COPY_PAYLOAD(e->payload, req->payload_size, req->payload);
|
|
|
+
|
|
|
bpf_map_delete_elem(&active_l7_requests, &k);
|
|
|
if (e->protocol == PROTOCOL_HTTP) {
|
|
|
- e->status = parse_http_status(args->buf);
|
|
|
+ response = is_http_response(payload, &e->status);
|
|
|
} else if (e->protocol == PROTOCOL_POSTGRES) {
|
|
|
- e->status = parse_postgres_status(args->buf, ret);
|
|
|
- if (request_type == POSTGRES_FRAME_PARSE) {
|
|
|
+ response = is_postgres_response(payload, ret, &e->status);
|
|
|
+ if (req->request_type == POSTGRES_FRAME_PARSE) {
|
|
|
e->method = METHOD_STATEMENT_PREPARE;
|
|
|
}
|
|
|
} else if (e->protocol == PROTOCOL_REDIS) {
|
|
|
- e->status = parse_redis_status(args->buf, ret);
|
|
|
+ response = is_redis_response(payload, ret, &e->status);
|
|
|
} else if (e->protocol == PROTOCOL_MEMCACHED) {
|
|
|
- e->status = parse_memcached_status(args->buf, ret);
|
|
|
+ response = is_memcached_response(payload, ret, &e->status);
|
|
|
} else if (e->protocol == PROTOCOL_MYSQL) {
|
|
|
- e->status = parse_mysql_response(args->buf, ret, request_type, &e->statement_id);
|
|
|
- if (request_type == MYSQL_COM_STMT_PREPARE) {
|
|
|
+ response = is_mysql_response(payload, ret, req->request_type, &e->statement_id, &e->status);
|
|
|
+ if (req->request_type == MYSQL_COM_STMT_PREPARE) {
|
|
|
e->method = METHOD_STATEMENT_PREPARE;
|
|
|
}
|
|
|
} else if (e->protocol == PROTOCOL_MONGO) {
|
|
|
- e->status = parse_mongo_status(args->buf, ret, partial);
|
|
|
- if (e->status == 1) {
|
|
|
+ response = is_mongo_response(payload, ret, req->partial);
|
|
|
+ if (response == 2) { // partial
|
|
|
struct l7_request *r = bpf_map_lookup_elem(&l7_request_heap, &zero);
|
|
|
if (!r) {
|
|
|
return 0;
|
|
|
}
|
|
|
r->partial = 1;
|
|
|
r->protocol = e->protocol;
|
|
|
- r->ns = ns;
|
|
|
- bpf_probe_read(r->payload, MAX_PAYLOAD_SIZE, e->payload);
|
|
|
+ r->ns = req->ns;
|
|
|
+ r->payload_size = req->payload_size;
|
|
|
+ COPY_PAYLOAD(r->payload, req->payload_size, req->payload);
|
|
|
bpf_map_update_elem(&active_l7_requests, &k, r, BPF_ANY);
|
|
|
return 0;
|
|
|
}
|
|
|
} else if (e->protocol == PROTOCOL_KAFKA) {
|
|
|
- e->status = parse_kafka_status(request_id, args->buf, ret, partial);
|
|
|
- } else if (e->protocol == PROTOCOL_CASSANDRA) {
|
|
|
- e->status = cassandra_status(cassandra_response);
|
|
|
+ response = is_kafka_response(payload, req->request_id);
|
|
|
}
|
|
|
- if (e->status == 0) {
|
|
|
+
|
|
|
+ if (!response) {
|
|
|
return 0;
|
|
|
}
|
|
|
- e->duration = bpf_ktime_get_ns() - ns;
|
|
|
+ e->duration = bpf_ktime_get_ns() - req->ns;
|
|
|
e->connection_timestamp = get_connection_timestamp(k.pid, k.fd);
|
|
|
bpf_perf_event_output(ctx, &l7_events, BPF_F_CURRENT_CPU, e, sizeof(*e));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+SEC("tracepoint/syscalls/sys_enter_write")
|
|
|
+int sys_enter_write(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
+ return trace_enter_write(ctx, ctx->fd, 0, ctx->buf, ctx->size, 0);
|
|
|
+}
|
|
|
+
|
|
|
SEC("tracepoint/syscalls/sys_enter_writev")
|
|
|
int sys_enter_writev(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
- struct iovec iovec0 = {};
|
|
|
- if (bpf_probe_read(&iovec0, sizeof(struct iovec), (void *)ctx->buf) < 0) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
- return trace_enter_write(ctx, ctx->fd, 0, iovec0.buf, iovec0.size);
|
|
|
+ return trace_enter_write(ctx, ctx->fd, 0, ctx->buf, 0, ctx->size);
|
|
|
}
|
|
|
|
|
|
-SEC("tracepoint/syscalls/sys_enter_write")
|
|
|
-int sys_enter_write(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
- return trace_enter_write(ctx, ctx->fd, 0, ctx->buf, ctx->size);
|
|
|
+SEC("tracepoint/syscalls/sys_enter_sendmsg")
|
|
|
+int sys_enter_sendmsg(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
+ struct user_msghdr msghdr = {};
|
|
|
+ if (bpf_probe_read(&msghdr, sizeof(msghdr), (void *)ctx->buf)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ return trace_enter_write(ctx, ctx->fd, 0, (char*)msghdr.msg_iov, 0, msghdr.msg_iovlen);
|
|
|
}
|
|
|
|
|
|
SEC("tracepoint/syscalls/sys_enter_sendto")
|
|
|
int sys_enter_sendto(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
- return trace_enter_write(ctx, ctx->fd, 0, ctx->buf, ctx->size);
|
|
|
+ return trace_enter_write(ctx, ctx->fd, 0, ctx->buf, ctx->size, 0);
|
|
|
}
|
|
|
|
|
|
SEC("tracepoint/syscalls/sys_enter_read")
|
|
|
int sys_enter_read(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
__u64 id = bpf_get_current_pid_tgid();
|
|
|
- return trace_enter_read(id, ctx->fd, ctx->buf, 0);
|
|
|
+ return trace_enter_read(id, ctx->fd, ctx->buf, 0, 0);
|
|
|
}
|
|
|
|
|
|
SEC("tracepoint/syscalls/sys_enter_readv")
|
|
|
int sys_enter_readv(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
__u64 id = bpf_get_current_pid_tgid();
|
|
|
- struct iovec iovec0 = {};
|
|
|
- if (bpf_probe_read(&iovec0, sizeof(struct iovec), (void *)ctx->buf) < 0) {
|
|
|
+ return trace_enter_read(id, ctx->fd, ctx->buf, 0, ctx->size);
|
|
|
+}
|
|
|
+
|
|
|
+SEC("tracepoint/syscalls/sys_enter_recvmsg")
|
|
|
+int sys_enter_recvmsg(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
+ __u64 id = bpf_get_current_pid_tgid();
|
|
|
+ struct user_msghdr msghdr = {};
|
|
|
+ if (bpf_probe_read(&msghdr, sizeof(msghdr), (void *)ctx->buf)) {
|
|
|
return 0;
|
|
|
}
|
|
|
- return trace_enter_read(id, ctx->fd, iovec0.buf, 0);
|
|
|
+ return trace_enter_read(id, ctx->fd, (char*)msghdr.msg_iov, 0, msghdr.msg_iovlen);
|
|
|
}
|
|
|
|
|
|
SEC("tracepoint/syscalls/sys_enter_recvfrom")
|
|
|
int sys_enter_recvfrom(struct trace_event_raw_sys_enter_rw__stub* ctx) {
|
|
|
__u64 id = bpf_get_current_pid_tgid();
|
|
|
- return trace_enter_read(id, ctx->fd, ctx->buf, 0);
|
|
|
+ return trace_enter_read(id, ctx->fd, ctx->buf, 0, 0);
|
|
|
}
|
|
|
|
|
|
SEC("tracepoint/syscalls/sys_exit_read")
|
|
|
@@ -429,6 +549,13 @@ int sys_exit_readv(struct trace_event_raw_sys_exit_rw__stub* ctx) {
|
|
|
return trace_exit_read(ctx, pid_tgid, pid, 0, ctx->ret);
|
|
|
}
|
|
|
|
|
|
+SEC("tracepoint/syscalls/sys_exit_recvmsg")
|
|
|
+int sys_exit_recvmsg(struct trace_event_raw_sys_exit_rw__stub* ctx) {
|
|
|
+ __u64 pid_tgid = bpf_get_current_pid_tgid();
|
|
|
+ __u32 pid = pid_tgid >> 32;
|
|
|
+ return trace_exit_read(ctx, pid_tgid, pid, 0, ctx->ret);
|
|
|
+}
|
|
|
+
|
|
|
SEC("tracepoint/syscalls/sys_exit_recvfrom")
|
|
|
int sys_exit_recvfrom(struct trace_event_raw_sys_exit_rw__stub* ctx) {
|
|
|
__u64 pid_tgid = bpf_get_current_pid_tgid();
|