libbpf eBPF对TCP下手了

eBPF这项新技术会成为又一个内核玩家们的新圣地。

而我对eBPF了解的越多,就愈发追捧这门技术,乃至有些痴迷,“eBPF造万物”的字眼快要在我嘴里破口而出,背后的原因,是内核给了eBPF足够的空间,去接管系统的一切。

但一个TCP玩家,学习eBPF的目的自然还是服务本源。TCP是我现在的工作,所以我只好把目光从全局回缩一下,先试着捣鼓eBPF对TCP的玩法。

BPF是我的新武器,所以我总想着在这玩出点什么名堂。

于是乎,我放弃了BCC这类框架,直接上手libbpf。

如果感兴趣,请戳下面链接:
有关BCC、libbpf和BPF CO-RE

刚接触eBPF,会偏执的认为这只是一个白盒测试,最有价值的是在于可以追踪应用程序/内核程序的一切信息,动态追踪是它的助燃器。尽管如此,我已经觉得eBPF很厉害了。

但玩了一段时间后,渐渐从BCC这些应用层框架的阵地偏向了kernel(kernel里实现了libbpf、bpftool等)。于是乎,我在kernel里熟悉着libbpf,bpftool、cgroup的同时,也掀开了BPF的幕帘。

eBPF 不仅能监控系统上的数据,甚至可以拿来改变系统的行为。

并且,它绝对安全!

对eBPF有了解的,大多都知道XDP可以在网络收发包的流程里,操作数据包内容,这也是XDP兴起的主要原因。但当内核协议栈拥有了实时处理数据包内容的能力时,相比XDP,就意味着不需要知道偏移量等背景信息,不需要考虑网络包分片的影响,在每个封包/解包的过程中去处理工作。在指定过程中自定义操作,如:二层对Ethernet头处理,三层对IP头处理,四层对TCP、UDP头处理等等。

所以,当你有需要对数据包内容进行自定义操作时,除了XDP,你也可以选用内核协议栈的BPF,(内核协议栈的ebpf技术实现依赖于libbpf)。

实例

最后,给出一个样例:在数据包TCP头部封装时,往TCP Options里注入IP:Port二元组。

// SPDX-License-Identifier: GPL-2.0
#include 
#include 
#include 
#include 
#include 
#include 

// * 程序版本信息
int _version SEC("version") = 1;

// reserved option number
 #define TCPOPT_TOA 77

struct tcp_option {
	__u8 kind;
	__u8 len;
	__u16 port;
    __u32 addr;
} __attribute__((packed));

SEC("sockops")
int bpf_tcpoptionstoa(struct bpf_sock_ops *skops)
{
    //return value for bpf program
	int rv = -1;
    //struct tcp_option option_buffer;
	int op = (int) skops->op;
    //update_event_map(op);
	switch (op) {
        //* client side
        case BPF_SOCK_OPS_TCP_CONNECT_CB:
            break;
        //* client side
        case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: {
            char fmt2[] = "client: active established\n";
            bpf_trace_printk(fmt2, sizeof(fmt2));
            /* Client will send option */
            //* BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG enables writing tcp options
            //* bpf_sock_ops_cb_flags_set用来调用修改flag的bpf程序——BPF_SOCK_OPS_HDR_OPT_LEN_CB/BPF_SOCK_OPS_WRITE_HDR_OPT_CB
            //* send new option from server side
            
            bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG);
            
            break;
        }
        // * server side
        case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:{
                char fmt3[] = "server: passive established\n";
                bpf_trace_printk(fmt3, sizeof(fmt3));
                /* Server will send option */
                //* BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG enables writing tcp options
                //* bpf_sock_ops_cb_flags_set用来调用修改flag的bpf程序——BPF_SOCK_OPS_HDR_OPT_LEN_CB/BPF_SOCK_OPS_WRITE_HDR_OPT_CB
                //* send new option from server side
                //bpf_sock_ops_cb_flags_set(skops, BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG);
                break;
            //return 1;
            //bpf_printk("rv := %d",rv);
        }
        case BPF_SOCK_OPS_HDR_OPT_LEN_CB: {
            
            //reserved space
            int option_len = sizeof(struct tcp_option);
            /* args[1] is the second argument */
            if (skops->args[1] + option_len <= 40) {
                rv = option_len;
            }
            else rv = 0;
            //* 保留空间已经验证成功
            // bpf_printk("option len is %d",rv);
		    bpf_reserve_hdr_opt(skops, rv, 0);
            // bpf_printk("err: %d",err);
            break;
        }

        case BPF_SOCK_OPS_WRITE_HDR_OPT_CB: {
            //bpf_printk("",skops->);
            struct tcp_option opt = {
                .kind = TCPOPT_TOA,
                .len  = 8,	// of this option struct
                .port = __bpf_htons(0xeB9F),
                .addr = __bpf_htonl(0x93d4860a),
            };
      
            / * Server sends option */
            // * write the option
            bpf_store_hdr_opt(skops, &opt, sizeof(opt), 0);
			// cancel the settings
            bpf_sock_ops_cb_flags_set(skops, skops->bpf_sock_ops_cb_flags& ~BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG);
            break;
        }
         
        default:
            rv = -1;
        }
	skops->reply = rv;
	return 1;
}
// * 必要的许可信息
char _license[] SEC("license") = "GPL";

你也完全可以对IP头部的IP Options做如上注入信息的操作。

结果

性能基准工具iperf3结合tcpdump数据包分析
libbpf eBPF对TCP下手了_第1张图片

你可能感兴趣的:(linux,tcp/ip,网络)