Skip to content

Commit 4e24875

Browse files
Close tutorial documentation and qdisc gates
1 parent e586e55 commit 4e24875

11 files changed

Lines changed: 379 additions & 216 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Tracing:
8989
- [lesson 39-nginx](src/39-nginx/README.md) Using eBPF to Trace Nginx Requests
9090
- [lesson 40-mysql](src/40-mysql/README.md) Using eBPF to Trace MySQL Queries
9191
- [lesson 48-energy](src/48-energy/README.md) Energy Monitoring for Process-Level Power Analysis
92-
- [lesson 52-fsession-latency](src/52-fsession-latency/README.md) Tracing Slow vfs_read Calls with fsession
92+
- [lesson 52-fsession-latency](src/52-fsession-latency/README.md) Trace Slow `vfs_read` Calls with fsession
9393

9494

9595
Security:
@@ -100,8 +100,8 @@ Security:
100100
- [lesson 27-replace](src/27-replace/README.md) Transparent Text Replacement in File Reads
101101
- [lesson 28-detach](src/28-detach/README.md) Running eBPF After Application Exits: The Lifecycle of eBPF Programs
102102
- [lesson 34-syscall](src/34-syscall/README.md) Modifying System Call Arguments with eBPF
103-
- [lesson 51-tcp-quarantine](src/51-tcp-quarantine/README.md) Precisely Isolating Established TCP Connections
104-
- [lesson 54-exec-image-inspector](src/54-exec-image-inspector/README.md) Inspecting the Executable Image After exec
103+
- [lesson 51-tcp-quarantine](src/51-tcp-quarantine/README.md) Destroy One Established TCP Connection Safely
104+
- [lesson 54-exec-image-inspector](src/54-exec-image-inspector/README.md) Continuously Inspect Executable Images After exec
105105

106106

107107
Features:

README.zh.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ GPU:
8888
- [lesson 39-nginx](src/39-nginx/README.zh.md) 使用 eBPF 跟踪 Nginx 请求
8989
- [lesson 40-mysql](src/40-mysql/README.zh.md) 使用 eBPF 跟踪 MySQL 查询
9090
- [lesson 48-energy](src/48-energy/README.zh.md) eBPF 教程:进程级能源监控与功耗分析
91-
- [lesson 52-fsession-latency](src/52-fsession-latency/README.zh.md) eBPF 教程:使用 fsession 追踪慢速 vfs_read 调用
91+
- [lesson 52-fsession-latency](src/52-fsession-latency/README.zh.md) eBPF 教程第五十二篇:使用 fsession 追踪慢速 `vfs_read`
9292

9393

9494
安全:
@@ -99,8 +99,8 @@ GPU:
9999
- [lesson 27-replace](src/27-replace/README.zh.md) 替换任意程序读取或者写入的文本
100100
- [lesson 28-detach](src/28-detach/README.zh.md) 在应用程序退出后运行 eBPF 程序:eBPF 程序的生命周期
101101
- [lesson 34-syscall](src/34-syscall/README.zh.md) eBPF 开发实践:使用 eBPF 修改系统调用参数
102-
- [lesson 51-tcp-quarantine](src/51-tcp-quarantine/README.zh.md) eBPF 教程:精准隔离已建立的 TCP 连接
103-
- [lesson 54-exec-image-inspector](src/54-exec-image-inspector/README.zh.md) eBPF 教程:检查 exec 后实际安装的可执行镜像
102+
- [lesson 51-tcp-quarantine](src/51-tcp-quarantine/README.zh.md) eBPF 教程第五十一篇:安全销毁一条已建立的 TCP 连接
103+
- [lesson 54-exec-image-inspector](src/54-exec-image-inspector/README.zh.md) eBPF 教程第五十四篇:持续检查 exec 后的可执行镜像
104104

105105

106106
特性:

src/51-tcp-quarantine/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ cd bpf-developer-tutorial/src/51-tcp-quarantine
139139
make
140140
```
141141

142+
Add `--verbose` only when you need libbpf loader diagnostics; it does not change socket selection.
143+
142144
First list the clients connected to the remote endpoint:
143145

144146
```console

src/51-tcp-quarantine/README.zh.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ cd bpf-developer-tutorial/src/51-tcp-quarantine
139139
make
140140
```
141141

142+
只有需要查看 libbpf 加载诊断时才加 `--verbose`;它不会改变 socket 选择范围。
143+
142144
首先列出连接到目标远端的客户端:
143145

144146
```console

src/53-egress-pacer/README.md

Lines changed: 119 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ The `SEC(".struct_ops")` block at the end registers the callbacks as a `Qdisc_op
384384
#include <linux/pkt_sched.h>
385385
#include <net/if.h>
386386
#include <signal.h>
387+
#include <spawn.h>
387388
#include <stdbool.h>
388389
#include <stdint.h>
389390
#include <stdio.h>
@@ -396,6 +397,8 @@ The `SEC(".struct_ops")` block at the end registers the callbacks as a `Qdisc_op
396397
#include "egress_pacer.h"
397398
#include "egress_pacer.skel.h"
398399
400+
extern char **environ;
401+
399402
static volatile sig_atomic_t exiting;
400403
401404
static struct env {
@@ -576,38 +579,137 @@ static int wait_for_duration(void)
576579
return 0;
577580
}
578581
582+
static const char *find_tc_binary(void)
583+
{
584+
static const char *const candidates[] = {
585+
"/usr/sbin/tc",
586+
"/sbin/tc",
587+
};
588+
size_t index;
589+
590+
for (index = 0; index < sizeof(candidates) / sizeof(candidates[0]); index++) {
591+
if (!access(candidates[index], X_OK))
592+
return candidates[index];
593+
}
594+
return NULL;
595+
}
596+
579597
static void print_current_qdisc(void)
580598
{
599+
const char *tc_binary = find_tc_binary();
600+
char *const arguments[] = {
601+
(char *)"tc", (char *)"qdisc", (char *)"show", (char *)"dev",
602+
(char *)env.interface, NULL,
603+
};
604+
posix_spawn_file_actions_t actions;
581605
pid_t child;
582606
pid_t waited;
607+
int error;
583608
int status;
584609
585610
fprintf(stderr, "current qdisc state:\n");
586-
child = fork();
587-
if (child < 0) {
588-
fprintf(stderr, "failed to run tc: %s\n", strerror(errno));
589-
return;
590-
}
591-
if (child == 0) {
592-
if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0)
593-
_exit(127);
594-
execlp("tc", "tc", "qdisc", "show", "dev", env.interface,
595-
(char *)NULL);
596-
_exit(127);
611+
if (!tc_binary) {
612+
fprintf(stderr, "tc was not found in /usr/sbin or /sbin\n");
613+
goto manual;
597614
}
598615
616+
error = posix_spawn_file_actions_init(&actions);
617+
if (error)
618+
goto spawn_failed;
619+
error = posix_spawn_file_actions_adddup2(&actions, STDERR_FILENO,
620+
STDOUT_FILENO);
621+
if (!error)
622+
error = posix_spawn(&child, tc_binary, &actions, NULL, arguments,
623+
environ);
624+
posix_spawn_file_actions_destroy(&actions);
625+
if (error)
626+
goto spawn_failed;
627+
599628
do {
600629
waited = waitpid(child, &status, 0);
601630
} while (waited < 0 && errno == EINTR);
602-
if (waited < 0 || !WIFEXITED(status) || WEXITSTATUS(status))
603-
fprintf(stderr, "run manually: tc qdisc show dev %s\n",
631+
if (waited >= 0 && WIFEXITED(status) && !WEXITSTATUS(status))
632+
return;
633+
if (waited < 0)
634+
error = errno;
635+
else
636+
error = EIO;
637+
638+
spawn_failed:
639+
fprintf(stderr, "failed to run tc: %s\n", strerror(error));
640+
manual:
641+
fprintf(stderr, "run manually: tc qdisc show dev %s\n", env.interface);
642+
}
643+
644+
static int install_pacer(struct egress_pacer_bpf *skel,
645+
struct bpf_tc_hook *hook)
646+
{
647+
int error;
648+
649+
error = egress_pacer_bpf__attach(skel);
650+
if (error) {
651+
if (error == -EEXIST) {
652+
fprintf(stderr,
653+
"bpf_pacer is already registered; a stale root qdisc may own it\n");
654+
print_current_qdisc();
655+
fprintf(stderr,
656+
"if it is stale, recover with: sudo tc qdisc del dev %s root\n",
657+
env.interface);
658+
} else {
659+
fprintf(stderr, "failed to register bpf_pacer qdisc: %s\n",
660+
strerror(-error));
661+
}
662+
return error;
663+
}
664+
665+
error = bpf_tc_hook_create(hook);
666+
if (!error)
667+
return 0;
668+
if (error == -EEXIST) {
669+
fprintf(stderr, "refusing to replace the existing root qdisc on %s\n",
604670
env.interface);
671+
print_current_qdisc();
672+
fprintf(stderr,
673+
"if it is stale, recover with: sudo tc qdisc del dev %s root\n",
674+
env.interface);
675+
} else {
676+
fprintf(stderr, "failed to attach bpf_pacer to %s: %s\n",
677+
env.interface, strerror(-error));
678+
}
679+
return error;
680+
}
681+
682+
static int cleanup_pacer(struct egress_pacer_bpf *skel,
683+
struct bpf_tc_hook *hook, bool qdisc_created, int error)
684+
{
685+
struct pacer_stats final_stats = {};
686+
int cleanup_error;
687+
688+
if (qdisc_created) {
689+
cleanup_error = bpf_tc_hook_destroy(hook);
690+
if (cleanup_error) {
691+
fprintf(stderr, "failed to remove bpf_pacer from %s: %s\n",
692+
env.interface, strerror(-cleanup_error));
693+
if (!error)
694+
error = cleanup_error;
695+
}
696+
}
697+
if (skel && skel->bss)
698+
final_stats = skel->bss->stats;
699+
if (qdisc_created) {
700+
printf("SUMMARY enqueued=%llu dequeued=%llu policy_dropped=%llu "
701+
"cleanup_dropped=%llu bytes_dequeued=%llu max_qlen=%llu\n",
702+
final_stats.enqueued, final_stats.dequeued,
703+
final_stats.policy_dropped, final_stats.cleanup_dropped,
704+
final_stats.bytes_dequeued, final_stats.max_qlen);
705+
}
706+
egress_pacer_bpf__destroy(skel);
707+
return error != 0;
605708
}
606709
607710
int main(int argc, char **argv)
608711
{
609712
struct egress_pacer_bpf *skel = NULL;
610-
struct pacer_stats final_stats = {};
611713
struct bpf_tc_hook hook = {
612714
.sz = sizeof(hook),
613715
.attach_point = BPF_TC_QDISC,
@@ -617,7 +719,6 @@ int main(int argc, char **argv)
617719
};
618720
bool qdisc_created = false;
619721
unsigned int ifindex;
620-
int cleanup_err;
621722
int err;
622723
623724
err = parse_args(argc, argv);
@@ -655,38 +756,9 @@ int main(int argc, char **argv)
655756
goto cleanup;
656757
}
657758
658-
err = egress_pacer_bpf__attach(skel);
659-
if (err) {
660-
if (err == -EEXIST) {
661-
fprintf(stderr,
662-
"bpf_pacer is already registered; a stale root qdisc may own it\n");
663-
print_current_qdisc();
664-
fprintf(stderr,
665-
"if it is stale, recover with: sudo tc qdisc del dev %s root\n",
666-
env.interface);
667-
} else {
668-
fprintf(stderr, "failed to register bpf_pacer qdisc: %s\n",
669-
strerror(-err));
670-
}
671-
goto cleanup;
672-
}
673-
674-
err = bpf_tc_hook_create(&hook);
675-
if (err) {
676-
if (err == -EEXIST) {
677-
fprintf(stderr,
678-
"refusing to replace the existing root qdisc on %s\n",
679-
env.interface);
680-
print_current_qdisc();
681-
fprintf(stderr,
682-
"if it is stale, recover with: sudo tc qdisc del dev %s root\n",
683-
env.interface);
684-
} else {
685-
fprintf(stderr, "failed to attach bpf_pacer to %s: %s\n",
686-
env.interface, strerror(-err));
687-
}
759+
err = install_pacer(skel, &hook);
760+
if (err)
688761
goto cleanup;
689-
}
690762
qdisc_created = true;
691763
692764
printf("READY interface=%s rate_kbps=%llu queue_limit=%u duration=%u\n",
@@ -696,26 +768,7 @@ int main(int argc, char **argv)
696768
err = wait_for_duration();
697769
698770
cleanup:
699-
if (qdisc_created) {
700-
cleanup_err = bpf_tc_hook_destroy(&hook);
701-
if (cleanup_err) {
702-
fprintf(stderr, "failed to remove bpf_pacer from %s: %s\n",
703-
env.interface, strerror(-cleanup_err));
704-
if (!err)
705-
err = cleanup_err;
706-
}
707-
}
708-
if (skel && skel->bss)
709-
final_stats = skel->bss->stats;
710-
if (qdisc_created) {
711-
printf("SUMMARY enqueued=%llu dequeued=%llu policy_dropped=%llu "
712-
"cleanup_dropped=%llu bytes_dequeued=%llu max_qlen=%llu\n",
713-
final_stats.enqueued, final_stats.dequeued,
714-
final_stats.policy_dropped, final_stats.cleanup_dropped,
715-
final_stats.bytes_dequeued, final_stats.max_qlen);
716-
}
717-
egress_pacer_bpf__destroy(skel);
718-
return err != 0;
771+
return cleanup_pacer(skel, &hook, qdisc_created, err);
719772
}
720773
```
721774

0 commit comments

Comments
 (0)