目录

XDP概述

XDP数据结构

XDP与eBPF的关系

XDP操作模式

XDP操作结果码

XDP和iproute2加载器

XDP和BCC


XDP概述

XDP是Linux网络路径上内核集成的数据包处理器,具有安全、可编程、高性能的特点。当网卡驱动程序收到数据包时,该处理器执行BPF程序。XDP可以在数据包进入协议栈之前就进行处理,因此具有很高的性能,可用于DDoS防御、防火墙、负载均衡等领域。

XDP数据结构

XDP程序使用的数据结构是xdp_buff,而不是sk_buffxdp_buff可以视为sk_buff的轻量级版本。
两者的区别在于:sk_buff包含数据包的元数据,xdp_buff创建更早,不依赖与其他内核层,因此XDP可以更快的获取和处理数据包。

xdp_buff数据结构定义如下:

// /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; /* perf critical, avoid false-sharing */struct xdp_buff {void *data;void *data_end;void *data_meta;void *data_hard_start;unsigned long handle;struct xdp_rxq_info *rxq;
};

sk_buff数据结构定义如下:

// /include/linux/skbuff.h
struct sk_buff {union {struct {/* These two members must be first. */struct sk_buff     *next;struct sk_buff        *prev;union {struct net_device  *dev;/* Some protocols might use this space to store information,* while device pointer would be NULL.* UDP receive path is one user.*/unsigned long        dev_scratch;};};struct rb_node      rbnode; /* used in netem, ip4 defrag, and tcp stack */struct list_head  list;};union {struct sock       *sk;int         ip_defrag_offset;};union {ktime_t       tstamp;u64      skb_mstamp_ns; /* earliest departure time */};/** This is the control buffer. It is free to use for every* layer. Please put your private variables there. If you* want to keep them across layers you have to do a skb_clone()* first. This is owned by whoever has the skb queued ATM.*/char          cb[48] __aligned(8);union {struct {unsigned long    _skb_refdst;void        (*destructor)(struct sk_buff *skb);};struct list_head   tcp_tsorted_anchor;};#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)unsigned long        _nfct;
#endifunsigned int      len,data_len;__u16          mac_len,hdr_len;/* Following fields are _not_ copied in __copy_skb_header()* Note that queue_mapping is here mostly to fill a hole.*/__u16          queue_mapping;/* if you move cloned around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define CLONED_MASK (1 << 7)
#else
#define CLONED_MASK 1
#endif
#define CLONED_OFFSET()     offsetof(struct sk_buff, __cloned_offset)__u8           __cloned_offset[0];__u8         cloned:1,nohdr:1,fclone:2,peeked:1,head_frag:1,xmit_more:1,pfmemalloc:1;
#ifdef CONFIG_SKB_EXTENSIONS__u8            active_extensions;
#endif/* fields enclosed in headers_start/headers_end are copied* using a single memcpy() in __copy_skb_header()*//* private: */__u32           headers_start[0];/* public: *//* if you move pkt_type around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define PKT_TYPE_MAX    (7 << 5)
#else
#define PKT_TYPE_MAX    7
#endif
#define PKT_TYPE_OFFSET()   offsetof(struct sk_buff, __pkt_type_offset)__u8         __pkt_type_offset[0];__u8           pkt_type:3;__u8         ignore_df:1;__u8            nf_trace:1;__u8         ip_summed:2;__u8            ooo_okay:1;__u8         l4_hash:1;__u8          sw_hash:1;__u8          wifi_acked_valid:1;__u8         wifi_acked:1;__u8           no_fcs:1;/* Indicates the inner headers are valid in the skbuff. */__u8         encapsulation:1;__u8            encap_hdr_csum:1;__u8           csum_valid:1;#ifdef __BIG_ENDIAN_BITFIELD
#define PKT_VLAN_PRESENT_BIT    7
#else
#define PKT_VLAN_PRESENT_BIT    0
#endif
#define PKT_VLAN_PRESENT_OFFSET()   offsetof(struct sk_buff, __pkt_vlan_present_offset)__u8         __pkt_vlan_present_offset[0];__u8           vlan_present:1;__u8         csum_complete_sw:1;__u8         csum_level:2;__u8           csum_not_inet:1;__u8            dst_pending_confirm:1;
#ifdef CONFIG_IPV6_NDISC_NODETYPE__u8           ndisc_nodetype:2;
#endif__u8          ipvs_property:1;__u8            inner_protocol_type:1;__u8          remcsum_offload:1;
#ifdef CONFIG_NET_SWITCHDEV__u8         offload_fwd_mark:1;__u8         offload_l3_fwd_mark:1;
#endif
#ifdef CONFIG_NET_CLS_ACT__u8           tc_skip_classify:1;__u8         tc_at_ingress:1;__u8            tc_redirected:1;__u8            tc_from_ingress:1;
#endif
#ifdef CONFIG_TLS_DEVICE__u8            decrypted:1;
#endif#ifdef CONFIG_NET_SCHED__u16          tc_index;   /* traffic control index */
#endifunion {__wsum     csum;struct {__u16  csum_start;__u16    csum_offset;};};__u32           priority;int            skb_iif;__u32           hash;__be16         vlan_proto;__u16            vlan_tci;
#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)union {unsigned int  napi_id;unsigned int    sender_cpu;};
#endif
#ifdef CONFIG_NETWORK_SECMARK__u32      secmark;
#endifunion {__u32      mark;__u32      reserved_tailroom;};union {__be16       inner_protocol;__u8     inner_ipproto;};__u16           inner_transport_header;__u16            inner_network_header;__u16          inner_mac_header;__be16         protocol;__u16          transport_header;__u16          network_header;__u16            mac_header;/* private: */__u32          headers_end[0];/* public: *//* These elements must be at the end, see alloc_skb() for details.  */sk_buff_data_t        tail;sk_buff_data_t     end;unsigned char       *head,*data;unsigned int        truesize;refcount_t     users;#ifdef CONFIG_SKB_EXTENSIONS/* only useable after checking ->active_extensions != 0 */struct skb_ext      *extensions;
#endif
};

XDP与eBPF的关系

XDP程序是通过bpf()系统调用控制的,bpf()系统调用使用程序类型BPF_PROG_TYPE_XDP进行加载。

XDP操作模式

XDP支持3种工作模式,默认使用native模式:

  • Native XDP:在native模式下,XDP BPF程序运行在网络驱动的早期接收路径上(RX队列),因此,使用该模式时需要网卡驱动程序支持。
  • Offloaded XDP:在Offloaded模式下,XDP BFP程序直接在NIC(Network Interface Controller)中处理数据包,而不使用主机CPU,相比native模式,性能更高
  • Generic XDP:Generic模式主要提供给开发人员测试使用,对于网卡或驱动无法支持native或offloaded模式的情况,内核提供了通用的generic模式,运行在协议栈中,不需要对驱动做任何修改。生产环境中建议使用native或offloaded模式

XDP操作结果码

  • XDP_DROP:丢弃数据包,发生在驱动程序的最早RX阶段
  • XDP_PASS:将数据包传递到协议栈处理,操作可能为以下两种形式:
    1、正常接收数据包,分配愿数据sk_buff结构并且将接收数据包入栈,然后将数据包引导到另一个CPU进行处理。他允许原始接口到用户空间进行处理。 这可能发生在数据包修改前或修改后。
    2、通过GRO(Generic receive offload)方式接收大的数据包,并且合并相同连接的数据包。经过处理后,GRO最终将数据包传入“正常接收”流
  • XDP_TX:转发数据包,将接收到的数据包发送回数据包到达的同一网卡。这可能在数据包修改前或修改后发生
  • XDP_REDIRECT:数据包重定向,XDP_TX,XDP_REDIRECT是将数据包送到另一块网卡或传入到BPF的cpumap中
  • XDP_ABORTED:表示eBPF程序发生错误,并导致数据包被丢弃。自己开发的程序不应该使用该返回码

XDP和iproute2加载器

iproute2工具中提供的ip命令可以充当XDP加载器的角色,将XDP程序编译成ELF文件并加载他。

  • 编写XDP程序xdp_filter.c,程序功能为丢弃所有TCP连接包,程序将xdp_md结构指针作为输入,相当于驱动程序xdp_buff的BPF结构。程序的入口函数为filter,编译后ELF文件的区域名为mysection。
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>#define SEC(NAME) __attribute__((section(NAME), used))SEC("mysection")
int filter(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(*eth);ip = data + ipsize;ipsize += sizeof(struct iphdr);if (data + ipsize > data_end) {return XDP_DROP;}if (ip->protocol == IPPROTO_TCP) {return XDP_DROP;}return XDP_PASS;
}
  • 将XDP程序编译为ELF文件
clang -O2 -target bpf -c xdp_filter.c -o xdp_filter.o
  • 使用ip命令加载XDP程序,将mysection部分作为程序的入口点
sudo ip link set dev ens33 xdp obj xdp_filter.o sec mysection

没有报错即完成加载,可以通过以下命令查看结果:

$ sudo ip a show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 xdpgeneric/id:56 qdisc fq_codel state UP group default qlen 1000link/ether 00:0c:29:2f:a8:41 brd ff:ff:ff:ff:ff:ffinet 192.168.136.140/24 brd 192.168.136.255 scope global dynamic noprefixroute ens33valid_lft 1629sec preferred_lft 1629secinet6 fe80::d411:ff0d:f428:ce2a/64 scope link noprefixroute valid_lft forever preferred_lft forever

其中,xdpgeneric/id:56说明使用的驱动程序为xdpgeneric,XDP程序id为56

  • 验证连接阻断效果
  1. 使用nc -l 8888监听8888 TCP端口,使用nc xxxxx 8888连接发送数据,目标主机未收到任何数据,说明TCP连接阻断成功
  2. 使用nc -kul 9999监听UDP 9999端口,使用nc -u xxxxx 9999连接发送数据,目标主机正常收到数据,说明UDP连接不受影响
  • 卸载XDP程序
$ sudo ip link set dev ens33 xdp off

卸载后,连接8888端口,发送数据,通信正常。

XDP和BCC

编写C代码xdp_bcc.c,当TCP连接目的端口为9999时DROP:

#define KBUILD_MODNAME "program"
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>int filter(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(*eth);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(9999)) {bpf_trace_printk("drop tcp dest port 9999\n");return XDP_DROP;}}return XDP_PASS;
}

与使用ip命令加载XDP程序类似,这里编写python加载程序实现对XDP程序的编译和内核注入。

#!/usr/bin/pythonfrom bcc import BPF
import timedevice = "ens33"
b = BPF(src_file="xdp_bcc.c")
fn = b.load_func("filter", BPF.XDP)
b.attach_xdp(device, fn, 0)try:b.trace_print()
except KeyboardInterrupt:passb.remove_xdp(device, 0)

验证效果,使用nc测试,无法与目标主机9999端口实现通信

$ sudo python xdp_bcc.py <idle>-0       [003] ..s. 22870.984559: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22871.987644: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22872.988840: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22873.997261: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22875.000567: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22876.002998: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22878.005414: 0: drop tcp dest port 9999
<idle>-0       [003] ..s. 22882.018119: 0: drop tcp dest port 9999

一文读懂eBPF/XDP相关推荐

  1. 从实验室走向大众,一文读懂Nanopore测序技术的发展及应用

    关键词/Nanopore测序技术    文/基因慧 随着基因测序技术不断突破,二代测序的发展也将基因检测成本大幅降低.理想的测序方法,是对原始DNA模板进行直接.准确的测序,消除PCR扩增带来的偏差, ...

  2. 一文读懂Faster RCNN

    来源:信息网络工程研究中心本文约7500字,建议阅读10+分钟 本文从四个切入点为你介绍Faster R-CNN网络. 经过R-CNN和Fast RCNN的积淀,Ross B. Girshick在20 ...

  3. 福利 | 一文读懂系列文章精选集发布啦!

    大数据时代已经悄然到来,越来越多的人希望学习一定的数据思维和技能来武装自己,虽然各种介绍大数据技术的文章每天都扑面而来,但纷繁又零散的知识常常让我们不知该从何入手:同时,为了感谢和回馈读者朋友对数据派 ...

  4. ​一文读懂EfficientDet

    一文读懂EfficientDet. 今年年初Google Brain团队在 CVPR 2020 上发布了 EfficientDet目标检测模型, EfficientDet是一系列可扩展的高效的目标检测 ...

  5. 一文读懂序列建模(deeplearning.ai)之序列模型与注意力机制

    https://www.toutiao.com/a6663809864260649485/ 作者:Pulkit Sharma,2019年1月21日 翻译:陈之炎 校对:丁楠雅 本文约11000字,建议 ...

  6. AI洞观 | 一文读懂英特尔的AI之路

    AI洞观 | 一文读懂英特尔的AI之路 https://mp.weixin.qq.com/s/E9NqeywzQ4H2XCFFOFcKXw 11月13日-14日,英特尔人工智能大会(AIDC)在北京召 ...

  7. 一文读懂机器学习中的模型偏差

    一文读懂机器学习中的模型偏差 http://blog.sina.com.cn/s/blog_cfa68e330102yz2c.html 在人工智能(AI)和机器学习(ML)领域,将预测模型参与决策过程 ...

  8. 一文读懂AI简史:当年各国烧钱许下的愿,有些至今仍未实现

    一文读懂AI简史:当年各国烧钱许下的愿,有些至今仍未实现 导读:近日,马云.马化腾.李彦宏等互联网大佬纷纷亮相2018世界人工智能大会,并登台演讲.关于人工智能的现状与未来,他们提出了各自的观点,也引 ...

  9. 一文读懂你该了解的5G知识:现在别买5G手机

    来源: 腾讯科技 2019年是中国全力布局5G的一年:三大运营商纷纷搭建基站,手机厂商发布5G手机,部分城市已经开启了5G测试--在电信日这天,腾讯科技联合知乎推出重磅策划,聚焦和5G相关的小知识,精 ...

最新文章

  1. mysql如何让自增id从某个位置开始设置方法
  2. 专属个人的聊天机器人的实现——图灵机器人
  3. C# 关于调用微信接口的代码
  4. python 多项式拟合
  5. 顺序表应用3:元素位置互换之移位算法
  6. .NET Core 2.x中使用Named Options处理多个强类型配置实例
  7. MySQL Oracle默认排序_PostgreSQL、MySQL、Oracle,查询的默认排序是怎样的?
  8. data=*(vu16*)addr;的理解?
  9. linux appium 安装教程,Ubuntu 系统安装 Appium 及样例运行教程
  10. 《WF本质论》第一章OpenSesame我的实现
  11. 颜色六位码和八位码表示
  12. 2019年最新淘宝联盟淘宝客升高佣规则
  13. 墙裂推荐6个优质公众号
  14. 【JavaSE】入门概述(1~41)
  15. 数据结构PTA习题:基础实验4-2.7 修理牧场 (25分)
  16. 图像的灰度化灰度值的读取Matlab
  17. 陈皓谈对待技术的态度
  18. extjs6 异步树
  19. 监听pda扫描_android系统PDA扫描枪,扫描完成后自带回车,为什么回车监听第一次不起作用,手动提交一次后才能正常提交...
  20. 从微软、FB、华为的网络安全备忘录说开去

热门文章

  1. 注册中心对比Zookeeper、Eureka、Nacos、Consul和Etcd
  2. UnityPlayerActivity详解
  3. 网络综合布线实训室解决方案
  4. 算法篇:神奇的卡塔兰数Catalan
  5. MySQL 8——学习笔记03(插入、更新、删除 数据 [DML语句]、查询数据 [DQL语句])
  6. 8c SQL手册 三
  7. TYPE-C接口安卓手机直播快充领夹式无线麦克风方案
  8. 常用网络ip地址有哪些
  9. 基于协同过滤算法的电影推荐系统
  10. 大批量其他经纬度转换为百度地图经纬度