Linux网络和eBPF

本文深入探讨了Linux系统中eBPF(Extended Berkeley Packet Filter)在网络层的应用,包括套接字选项、消息传递、映射、过滤器和流量控制程序。eBPF提供数据包捕获、过滤、流量控制等能力,可在service mesh和云原生环境中发挥重要作用。文章介绍了如何使用BPF程序实现套接字操作,如SOCK_OPS、SK_MSG、SK_SKB,以及如何利用BPF实现套接字重定向和内核级负载均衡。此外,还讨论了流量控制分类器如socket过滤器和TC子系统的BPF程序,展示了它们在数据包调度和流量整形中的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于本文

Linux 现在已经支持了很多种和网络相关的 eBPF 程序了,这些程序可以附加到任何套接字上,可以提取流经数据包的相关信息,可以检测和控制系统的网络流量,可以对网络接口的数据包进行过滤,可以对数据包进行放行、禁止或重定向等,可以修改网络连接状态…这些能力在 service mesh,云原生[2][3]等场景下有极大的作用,本文会介绍一些 eBPF 程序在网络上的应用。

如何实现

从网络的角度来看,使用 BPF 程序主要有两个用途: 数据包捕获过滤 [1]。
它这些能力的实现主要取决与以下两种类型的程序:

  • 套接字相关程序
  • 基于 BPF 分类器和流量控制程序

网络相关的 eBPF 程序通常会需要传一个参数 struct __sk_buff,我们先来看看他的结构[4][5]:

struct __sk_buff {
   
	__u32 len; /* 整个数据区域的长度, 这个 len 只计算有效的协议长度,如果在 l3 时, 不会计算 l2 的协议头长度*/
	__u32 pkt_type; /*标记帧的类型*/
	__u32 mark;
	__u32 queue_mapping;
	__u32 protocol; /*协议类型*/
	__u32 vlan_present;
	__u32 vlan_tci;
	__u32 vlan_proto;
	__u32 priority;
	__u32 ingress_ifindex;
	__u32 ifindex;
	__u32 tc_index; /* traffic control index */
	__u32 cb[5]; /* 保存与协议相关的控制信息, 每个协议可以独立使用这些信息*/
	__u32 hash;
	__u32 tc_classid;
	__u32 data; // 数据开始指针
	__u32 data_end; // 数据结束指针
	__u32 napi_id;

	/* Accessed by BPF_PROG_TYPE_sk_skb types from here to ... */
	__u32 family;
	__u32 remote_ip4;	/* Stored in network byte order */
	__u32 local_ip4;	/* Stored in network byte order */
	__u32 remote_ip6[4];	/* Stored in network byte order */
	__u32 local_ip6[4];	/* Stored in network byte order */
	__u32 remote_port;	/* Stored in network byte order */
	__u32 local_port;	/* stored in host byte order */
	/* ... here. */

	__u32 data_meta;
	__bpf_md_ptr(struct bpf_flow_keys *, flow_keys);
	__u64 tstamp;
	__u32 wire_len;
	__u32 gso_segs;
	__bpf_md_ptr(struct bpf_sock *, sk);
	__u32 gso_size;
	__u32 :32;		/* Padding, future use. */
	__u64 hwtstamp;
};

它是对内核网络核心结构 struct sk_buff 的用户可访问字段的镜像。BPF 程序中对 struct __sk_buff 字段的访问,将会被 BPF 校验器转换成对相应的 struct sk_buff 字段的访问[7]。而 sk_buff 是 Linux 网络协议栈里最重要的结构体,它用来管理和控制接受或发送数据包,在内核中各个协议之间传输时,不需要拷贝 sk_buff 的数据,只需要改协议头和移动数据指针,当数据从 L4 到 L2 时,数据段只用移动 sk_buff 里的 data 指针即可 。
BPF 程序通过访问 __sk_buff 中暴露的这些数据 ,可以选择放行(PASS)或丢弃(DROP)数据包; 可以将当前流量信息保存到 BPF 映射 来统计流量数据。甚至在一部分 BPF 程序里,可以对这些数据包进行重定向或改变其基本结构[1]。
可以说 __sk_buff

Linux系统中,eBPF(Extended Berkeley Packet Filter)技术可以用来调试监控网络行为。对于网络调试,bpftool工具是常用的辅助工具之一。`bpftool net show dev ens33 -p`命令[^1]可用于查看特定设备(如ens33)上的eBPF hook点,这些hook点允许在关键路径上插入自定义的代码。 具体来说,要使用eBPF进行网络调试,你可以编写eBPF程序来追踪系统调用,比如当一个进程试图加载一个新的eBPF程序时。在Linux内核中,所有eBPF操作都依赖于系统调用`SYS_BPF`。在这个例子中,开发者定义了一个名为`tracepoint_sys_enter_bpf`的tracepoint,该tracepoint会在`sys_enter_bpf`(进入BPF系统调用时)触发。当这个系统调用发生时,会捕获相关信息并发送事件。 下面是一个简单的概念性示例,展示了如何在`sys_enter_bpf`时创建一个事件: ```c SEC("tracepoint/syscalls/sys_enter_bpf") int tracepoint_sys_enter_bpf(struct syscall_bpf_args *args) { struct bpf_context_t *bpf_context = make_event(); if (!bpf_context) return 0; bpf_context->cmd = args->cmd; get_common_proc(&bpf_context->procinfo); send_event(args, bpf_context); return 0; } ``` 这段代码说明了在`sys_enter_bpf`时,它会创建一个`bpf_context`结构体,存储传入的参数(`args->cmd`),获取进程信息,然后发送一个事件。这只是一个基本框架,实际应用可能需要更复杂的逻辑以满足特定的监控需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Randy__Lambert

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值