高性能网络框架——XDP

摘要

    为了提升服务器处理网络流量的性能,涌现了一些技术,XDP就是其中的一种。XDP 是一种 Linux 下的基于 eBPF 实现的内核旁路技术,是一个位于内核协议栈之前的数据包处理器,并拥有将数据包绕过内核协议栈重定向至应用层的能力,因此具有很高的性能,可用于DDoS防御、防火墙、负载均衡等领域。

XDP 架构

        XDP 工作在驱动层,位于物理网卡与内核协议栈之间的部分。其支持 3 种工作模式,

        分别是:

  • Native:在此模式下,XDP BPF 程序运行在网络驱动的早期接收路径上(RX队列),因此,使用该模式时需要网卡驱动程序支持,性能很高。
  • Offloaded:在此模式下,XDP BFP程序直接在NIC(Network Interface Controller)中处理数据包,而不使用主机CPU,相比 Native 模式,性能最高,但需要硬件支持。
  • Generic:对于网卡或驱动无法支持 Native 或 Offloaded 模式的情况,内核提供了通用的generic模式,运行在协议栈入口处,不需要对驱动做任何修改,此模式性能不如前两者。

        其中,Native 模式最为常见,为默认使用的模式。

返回码

        类似于 netfilter 框架,其上的 hook 点对数据包的处理有 drop 或者 pass 返回码,XDP 也有一套类似的返回码。

  • XDP_DROP:丢弃数据包。
  • XDP_PASS:放行数据包,数据包接下来将走到协议栈。
  • XDP_TX:转发数据包,将接收到的数据包发送回数据包到达的同一网卡。一般为 echo 响应时将数据包简单修改后发送出去的场景下使用。
  • XDP_REDIRECT:数据包重定向,将数据包送到其它网卡发送或者是传给 eBPF 的 map 交给用户程序。

Test

        试着编写一个简单的 XDP 代码,丢弃掉目的端口为 6666 的 TCP 报文:

#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>

/* linux/include/net/xdp.h
struct xdp_rxq_info {
	struct net_device *dev;
	u32 queue_index;
	u32 reg_state;
	struct xdp_mem_info mem;
} ____cacheline_aligned;

struct xdp_buff {
	void *data;
	void *data_end;
	void *data_meta;
	void *data_hard_start;
	unsigned long handle;
	struct xdp_rxq_info *rxq;
};
*/

int test(struct xdp_md *ctx) {
    int ipsize = 0;
    void *data = (void *)(long)ctx->data;
    void *data_end = (void *)(long)ctx->data_end;
    struct ethhdr *eth = data;
    struct iphdr *ip;

    ipsize = sizeof(struct ethhdr);
    ip = data + ipsize;

    ipsize += sizeof(struct iphdr);
    if (data + ipsize > data_end) {
        return XDP_DROP;
    }

    if (ip->protocol == IPPROTO_TCP) {
        struct tcphdr *tcp = (void *)ip + sizeof(*ip);
        ipsize += sizeof(struct tcphdr);
        if (data + ipsize > data_end) {
            return XDP_DROP;
        }

        if (tcp->dest == ntohs(6666)) {
            bpf_trace_printk("drop tcp dst port 6666\n");
            return XDP_DROP;
        }
    }

    return XDP_PASS;
}

        作为一个 eBPF 程序,当然还是需要一个加载器将其加载到 kernel 中去执行才行,用 python 来实现这个加载器比较方便:

#!/usr/bin/python3

from bcc import BPF
import time
import sys

if len(sys.argv) <= 3:
    print("Usage: %s xxx.c func dev" % (sys.argv[0]))
    exit(0)

src_file = sys.argv[1]
func = sys.argv[2]
device = sys.argv[3]

bpf = BPF(src_file)
fn = bpf.load_func(func, BPF.XDP)
bpf.attach_xdp(device, fn, 0)

try:
    bpf.trace_print()
except KeyboardInterrupt:
    pass

bpf.remove_xdp(device, 0)

         调用加载器将 XDP 测试程序加载到 eth0 上试试:

[root@localhost ebpf]# ./xdp_load.py xdp_test.c test eth0

        然后在另一台机器上给这个网卡发包:

C:\Users\kevin>telnet 172.29.10.208 6666

        It's work on my  machine!

        这个只是最简单的应用,下次再学习一下把数据重定向到应用层。

        最后还是附上一下源码:https://github.com/Fireplusplus/Linux/tree/master/ebpf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Fireplusplus

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

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

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

打赏作者

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

抵扣说明:

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

余额充值