在函数之间共享信息(BPF/XDP)
share information between function(BPF/XDP)
Objective: If process id/name = xxx then drop the packet
所以,我有点困惑。到目前为止,我知道您无法从 XDP 中提取进程信息,但 bpf trace 允许您跟踪它。
这是我可能的解决方案,使用 bpf 哈希映射在两个函数之间共享信息。如果进程名称 == xx 则 XDP_DROP。 (这可能是错误的,但我正在尝试)
但是我不知道如何使用BPF_HASHMAPS,我还没有阅读关于密件抄送的文档..
示例:从这个 hello 函数我可以跟踪事件
struct data_t {
u32 pid;
u64 ts;
char comm[TASK_COMM_LEN];
};
BPF_PERF_OUTPUT(events);
int hello(struct pt_regs *ctx) {
struct data_t data = {};
data.pid = bpf_get_current_pid_tgid();
data.ts = bpf_ktime_get_ns();
bpf_get_current_comm(&data.comm, sizeof(data.comm));
events.perf_submit(ctx, &data, sizeof(data));
return 0;
}
用于删除打包程序的 XDP 函数
int udpfilter(struct xdp_md *ctx) {
bpf_trace_printk("got a packet\n");
//u32 cpu = bpf_get_smp_processor_id();
//bpf_trace_printk("%s looking\n",cpu);
//u32 pid = bpf_get_current_pid_tgid();
return XDP_DROP;
}
现在如何获取 pid 值并在 XDP 函数中使用它,加上解决方案是否有意义。感谢您的帮助,非常感谢。
因此,如您所知,eBPF 程序可以在不同位置加载到内核中。 XDP 程序在网络驱动程序之后和网络堆栈之前加载。此时内核不知道数据包可能是哪个进程的,因为它将在网络堆栈中计算出所有这些。
您显示的 hello
程序是 kprobe(内核探测)的一个示例。它附加到您指定的任何内核函数,但它是一个跟踪工具,无法进行更改。
此外,一些辅助函数如 bpf_get_current_pid_tgid
依赖于程序类型。 bpf_get_current_pid_tgid
仅适用于 kprobes、uprobes、tracepoint 程序(perf 程序),实际上可能也适用于 socket 和 cGroup 程序,问题是没有一个非常明确的列表或概述哪些工作在哪里,这些是两个不错但不全面的链接:
- https://blogs.oracle.com/linux/post/bpf-in-depth-bpf-helper-functions
- https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#program-types
最后归结为逻辑。内核只能让您访问它自己可以访问的数据和操作。因此,如果你想根据进程 ID 做网络相关的事情,你可能需要使用附加在此类信息可用位置的 eBPF 程序(请记住,这显然也更慢)。
因此,根据您具体想要做什么,您有以下几种选择:
- 将 eBPF 程序附加到网络套接字 (
BPF_PROG_TYPE_SOCKET_FILTER
),以便您可以在套接字级别过滤数据包。这确实需要创建套接字的程序将程序附加到它。
- 使用 cGroup 和
BPF_PROG_TYPE_CGROUP_SKB
程序来阻止数据包。由于您将程序附加到cGroup,因此不需要程序的配合。
- 使用TC程序(
BPF_PROG_TYPE_SCHED_ACT
),在这个级别上已经解析了一个数据包,但您仍然需要将其匹配到一个进程
- 使用XDP程序(
BPF_PROG_TYPE_XDP
)还是可以的,这个需要你解析所有层的网络包(Ethernet, VLAN, IP, UDP/TCP),然后手动提取协议、目标 IP 和目标端口。就像在 TC 程序中一样,您需要使用查找 table. 将其与 pid 匹配
走 XDP 或 TC 路线时,您需要创建此查找 table。据我所知,您无法通过辅助函数访问内核的 table 。一些方法是:
- 解析
netstat -lpn
的输出(协议、目标ip、目标端口和PID)并在映射中设置数据以供程序使用
- 直接从 /sys 或 /proc 获取相同的数据(我不知道数据到底存储在哪里)
- 在创建过程中记录哪些 PID 具有哪些套接字(使用第二个程序(kprobe/tracepoint))并将此数据设置在由 XDP/TC 程序和跟踪程序共享的映射中。 (不太确定如何在 BCC 中的程序之间共享映射,但使用 libbpf 时肯定可以)
Objective: If process id/name = xxx then drop the packet 所以,我有点困惑。到目前为止,我知道您无法从 XDP 中提取进程信息,但 bpf trace 允许您跟踪它。 这是我可能的解决方案,使用 bpf 哈希映射在两个函数之间共享信息。如果进程名称 == xx 则 XDP_DROP。 (这可能是错误的,但我正在尝试)
但是我不知道如何使用BPF_HASHMAPS,我还没有阅读关于密件抄送的文档..
示例:从这个 hello 函数我可以跟踪事件
struct data_t {
u32 pid;
u64 ts;
char comm[TASK_COMM_LEN];
};
BPF_PERF_OUTPUT(events);
int hello(struct pt_regs *ctx) {
struct data_t data = {};
data.pid = bpf_get_current_pid_tgid();
data.ts = bpf_ktime_get_ns();
bpf_get_current_comm(&data.comm, sizeof(data.comm));
events.perf_submit(ctx, &data, sizeof(data));
return 0;
}
用于删除打包程序的 XDP 函数
int udpfilter(struct xdp_md *ctx) {
bpf_trace_printk("got a packet\n");
//u32 cpu = bpf_get_smp_processor_id();
//bpf_trace_printk("%s looking\n",cpu);
//u32 pid = bpf_get_current_pid_tgid();
return XDP_DROP;
}
现在如何获取 pid 值并在 XDP 函数中使用它,加上解决方案是否有意义。感谢您的帮助,非常感谢。
因此,如您所知,eBPF 程序可以在不同位置加载到内核中。 XDP 程序在网络驱动程序之后和网络堆栈之前加载。此时内核不知道数据包可能是哪个进程的,因为它将在网络堆栈中计算出所有这些。
您显示的 hello
程序是 kprobe(内核探测)的一个示例。它附加到您指定的任何内核函数,但它是一个跟踪工具,无法进行更改。
此外,一些辅助函数如 bpf_get_current_pid_tgid
依赖于程序类型。 bpf_get_current_pid_tgid
仅适用于 kprobes、uprobes、tracepoint 程序(perf 程序),实际上可能也适用于 socket 和 cGroup 程序,问题是没有一个非常明确的列表或概述哪些工作在哪里,这些是两个不错但不全面的链接:
- https://blogs.oracle.com/linux/post/bpf-in-depth-bpf-helper-functions
- https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#program-types
最后归结为逻辑。内核只能让您访问它自己可以访问的数据和操作。因此,如果你想根据进程 ID 做网络相关的事情,你可能需要使用附加在此类信息可用位置的 eBPF 程序(请记住,这显然也更慢)。
因此,根据您具体想要做什么,您有以下几种选择:
- 将 eBPF 程序附加到网络套接字 (
BPF_PROG_TYPE_SOCKET_FILTER
),以便您可以在套接字级别过滤数据包。这确实需要创建套接字的程序将程序附加到它。 - 使用 cGroup 和
BPF_PROG_TYPE_CGROUP_SKB
程序来阻止数据包。由于您将程序附加到cGroup,因此不需要程序的配合。 - 使用TC程序(
BPF_PROG_TYPE_SCHED_ACT
),在这个级别上已经解析了一个数据包,但您仍然需要将其匹配到一个进程 - 使用XDP程序(
BPF_PROG_TYPE_XDP
)还是可以的,这个需要你解析所有层的网络包(Ethernet, VLAN, IP, UDP/TCP),然后手动提取协议、目标 IP 和目标端口。就像在 TC 程序中一样,您需要使用查找 table. 将其与 pid 匹配
走 XDP 或 TC 路线时,您需要创建此查找 table。据我所知,您无法通过辅助函数访问内核的 table 。一些方法是:
- 解析
netstat -lpn
的输出(协议、目标ip、目标端口和PID)并在映射中设置数据以供程序使用 - 直接从 /sys 或 /proc 获取相同的数据(我不知道数据到底存储在哪里)
- 在创建过程中记录哪些 PID 具有哪些套接字(使用第二个程序(kprobe/tracepoint))并将此数据设置在由 XDP/TC 程序和跟踪程序共享的映射中。 (不太确定如何在 BCC 中的程序之间共享映射,但使用 libbpf 时肯定可以)