套接字缓存之sk_buff结构

https://www.cnblogs.com/wanpengcoder/p/7529486.html 来此此处

sk_buff结构用来描述已接收或者待发送的数据报文信息;skb在不同网络协议层之间传递,可被用于不同网络协议,如二层的以太网协议,三层的ip协议,四层的tcp或者udp协议,其中某些成员变量会在该结构从一层向另一层传递时发生改变,从上层向下层传递需要添加首部,从下层向上层传递需要移除首部;

多个skb通过sk_buff_head表头部结构的next和prev指针连接成双向链表;头部还包含了链表中skb节点的总数量;

/* skb头结构 */
struct sk_buff_head {
/* These two members must be first. */
/* 通过下面两个指针成员将skb连接成双向链表 */
struct sk_buff *next; /* 指向后一个skb */
struct sk_buff *prev; /* 指向前一个skb */ __u32 qlen; /* 链表中元素个数 */
spinlock_t lock; /* 自旋锁 */
};

2/

/* skb结构 */
struct sk_buff {
union {
struct {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev; /* 报文到达或者离开的时间戳 */
union {
ktime_t tstamp;
struct skb_mstamp skb_mstamp;
};
};
/* 红黑树的节点,用在netem和tcp协议栈 */
struct rb_node rbnode; /* used in netem & tcp stack */
}; /*
指向缓冲区的套接字sock数据结构。当数据在本地产生或者正由本地进程接收时,
该数据以及套接字相关信息会被L4(tcp或者udp)以及用户应用程序使用
当缓冲区只是被转发时(本地机器不是来源也不是目的地),该指针为NULL
*/
struct sock *sk; 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;
};
/*
* 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); /* 路由缓存,输入或者输出报文都要查询到目的路由缓存项,才能确定流向 */
unsigned long _skb_refdst; /*
当缓冲区被删除时,可以完成某些清理工作
当缓冲区不属于一个套接字时,该函数通常不被初始化
属于一个套接字时,通常设置为sock_rfree或sock_wfree
sock_xxx函数用于更新套接字队列中所持有的内存
*/
void (*destructor)(struct sk_buff *skb);
#ifdef CONFIG_XFRM
/* ipsec用于跟踪传输信息 */
struct sec_path *sp;
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
/* 连接跟踪 */
unsigned long _nfct;
#endif
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
/* 桥接帧的相关信息 */
struct nf_bridge_info *nf_bridge;
#endif
/*
缓冲区的数据区块大小,该长度包括主缓冲区(head指针指向)的数据
以及一些片段(fragment)的数据,当缓冲区从一个网络分层移动到下一个
网络分层时,该值会发生变化,因为在协议栈中向上层移动时报头会被丢弃
向下层移动时报头会添加,len也会把协议报头算在内,与"数据预留和对齐"操作
*/
unsigned int len,
/* 片段(fragment)中的数据大小 */
data_len;
/* mac报头大小 */
__u16 mac_len,
/* 克隆skb时可写报文头部长度 */
hdr_len; /* Following fields are _not_ copied in __copy_skb_header()
* Note that queue_mapping is here mostly to fill a hole.
*/
kmemcheck_bitfield_begin(flags1);
/* 多设备的队列映射 */
__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];
/* 表示该skb是另外一个skb的克隆 */
__u8 cloned:1,
/*
payload是否被单独引用,不存在协议首部,如果被引用,则不能修改协议首部,
也不能通过skb->data来访问协议首部
*/
nohdr:1,
/*
当前克隆状态
SKB_FCLONE_UNAVAILABLE-skb未被克隆
SKB_FCLONE_ORIG-在skbuff_fclone_cache分配的父skb,可以被克隆
SKB_FCLONE_CLONE-在skbuff_fclone_cache分配的子skb,从父skb克隆得到
*/
fclone:2,
peeked:1,
/* 通过page_fragment_alloc分配内存 */
head_frag:1,
xmit_more:1,
__unused:1; /* one bit hole */
kmemcheck_bitfield_end(flags1); /* 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];
/*
此字段根据l2的目的地址进行划分
PACKET_HOST-mac地址与接收设备mac地址相等,说明是发给该主机的
PACKET_BROADCAST-mac地址是接收设备的广播地址
PACKET_MULTICAST-mac地址接收改设备注册的多播地址之一
PACKET_OTHERHOST-mac地址不属于接收设备的地址,启用转发则转发,否则丢弃
PACKET_OUTGOING-数据包将被发出,用到这个标记的功能包括decnet,或者为每个
网络tab都复制一份发出包的函数
PACKET_LOOPBACK-数据包发往回环设备,有此标识,处理回环设备时,
可以跳过一些真实设备所需的操作
PACKET_USER-发送到用户空间,netlink使用
PACKET_KERNEL-发送到内核空间,netlink使用
PACKET_FASTROUTE-未使用
*/
__u8 pkt_type:3;
/* PFMEMALLOC内存分配标记 */
__u8 pfmemalloc:1;
__u8 ignore_df:1; __u8 nf_trace:1;
/*
CHECKSUM_NONE-硬件不支持,完全由软件执行校验和
CHECKSUM_PARTIAL-由硬件来执行校验和
CHECKSUM_UNNECESSARY-没必要执行校验和
CHECKSUM_COMPLETE-已完成执行校验和
*/
__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;
__u8 csum_complete_sw:1;
__u8 csum_level:2;
__u8 csum_bad: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;
#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_NET_SCHED
__u16 tc_index; /* traffic control index */
#endif union {
/* 校验和,必须包含csum_start和csum_offset */
__wsum csum;
struct {
/* 校验开始位置,相对于header */
__u16 csum_start;
/* 校验和存储位置,相对于csum_start */
__u16 csum_offset;
};
};
/*
正在被传输的数据包QoS等级
数据包由本地产生,套接字会定义优先级的值
数据包在被转发,则在调用ip_forward函数时,会根据
ip头本身的ToS字段定义该值
*/
__u32 priority;
/* 数据包接收时的网络设备索引号 */
int skb_iif;
/* 数据包的hash值 */
__u32 hash;
/* vlan封装协议 */
__be16 vlan_proto;
/* vlan标签控制信息 */
__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;
#endif union {
__u32 mark;
__u32 reserved_tailroom;
}; /* 封装的协议 */
union {
__be16 inner_protocol;
__u8 inner_ipproto;
};
/* 封装的传输层头部相对于head的偏移 */
__u16 inner_transport_header;
/* 封装的网络层头部相对于head的偏移 */
__u16 inner_network_header;
/* 封装的链路层头部相对于head的偏移 */
__u16 inner_mac_header; /*
l3层协议值
如ETH_P_IP-ipv4报文
ETH_P_ARP-arp报文等
*/
__be16 protocol;
/* 传输层头部相对于head的偏移 */
__u16 transport_header;
/* 网络层头部相对于head的偏移 */
__u16 network_header;
/* 链路层头部相对于head的偏移 */
__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;
/*
缓冲区的总大小,包括skb本身和实际数据len大小,alloc_skb函数将
该字段设置为len+sizeof(sk_buff)
每当len值更新,该值也要对应更新
*/
unsigned int truesize; /*
引用计数,在使用该skb缓冲区的实例个数,当引用计数为0时,skb才能被释放
skb_get()获取操作中会增加引用计数,kfree_skb释放过程中检查引用计数,
引用计数为0时,才真正释放skb
该计数器只计算sk_buff结构引用计数,缓冲区包含的实际数据由
skb_shared_info->dataref字段记录
*/
atomic_t users;
};

sk_buff结构--转载的更多相关文章

  1. sk_buff结构

    sk_buff结构用来描述已接收或者待发送的数据报文信息:skb在不同网络协议层之间传递,可被用于不同网络协议,如二层的mac或其他链路层协议,三层的ip,四层的tcp或者udp协议,其中某些成员变量 ...

  2. Linux 内核网络协议栈 ------sk_buff 结构体 以及 完全解释 (2.6.16)

    转自:http://blog.csdn.net/shanshanpt/article/details/21024465 在2.6.24之后这个结构体有了较大的变化,此处先说一说2.6.16版本的sk_ ...

  3. windows进程中的内存结构[转载]

    在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识. 接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据.那么这些变量在内存中是如何存放的呢?程序又是如何使用这些变 ...

  4. 解读eXtremeComponents代码结构--转载

    原文地址:http://blog.csdn.net/lark3/article/details/1937466 大致整理了去年写的东西,罗列如下: ec是一系列提供高级显示的开源JSP定制标签,当前的 ...

  5. 使用Python比较MySQL数据库中两个数据库的表结构--转载

    https://blog.csdn.net/tenaguan4461/article/details/82286781 https://www.jianshu.com/p/b3dac5a3479a

  6. sk_buff封装和解封装网络数据包的过程详解(转载)

    http://dog250.blog.51cto.com/2466061/1612791 可以说sk_buff结构体是Linux网络协议栈的核心中的核心,几乎所有的操作都是围绕sk_buff这个结构体 ...

  7. 【Linux 内核网络协议栈源码剖析】网络栈主要结构介绍(socket、sock、sk_buff,etc)

    原文:http://blog.csdn.net/wenqian1991/article/details/46700177 通过前面的分析,可以发现,网络协议栈中的数据处理,都是基于各类结构体,所有有关 ...

  8. [转载] epoll详解

    转载自http://blog.csdn.net/xiajun07061225/article/details/9250579 什么是epoll epoll是什么?按照man手册的说法:是为处理大批量句 ...

  9. Linux 网络设备驱动开发(一) —— linux内核网络分层结构

    Preface Linux内核对网络驱动程序使用统一的接口,并且对于网络设备采用面向对象的思想设计. Linux内核采用分层结构处理网络数据包.分层结构与网络协议的结构匹配,既能简化数据包处理流程,又 ...

随机推荐

  1. 从面试角度学完 Kafka

    Kafka 是一个优秀的分布式消息中间件,许多系统中都会使用到 Kafka 来做消息通信.对分布式消息系统的了解和使用几乎成为一个后台开发人员必备的技能.今天码哥字节就从常见的 Kafka 面试题入手 ...

  2. day45 Pyhton 数据库Mysql 02

    一.前期回顾 数据库 mysql的安装 配置环境 为什么要用数据库? 稳定性 一致性 并发 存取数据效率高 数据库的分类 关系型数据库 mysql oracle sqlserver 非关系型数据库 r ...

  3. Jenkins+pytest+Allure搭建自动化测试

    持续集成(CONTINUOUS INTEGRATION) 在CI环境中,开发人员将会频繁地向主干提交代码.这些新提交的代码在最终合并到主干前,需要经过编译和自动化测试流进行验证. 持续交付(CONTI ...

  4. 【9】进大厂必须掌握的面试题-DevOps面试

    Q1.DevOps和Agile之间的根本区别是什么? 下表中列出了两者之间的差异. 特征 DevOps--开发运维 Agile--敏捷 敏捷 开发和运营中的敏捷性 只有发展才能敏捷 流程/实践 涉及C ...

  5. spring boot:thymeleaf给fragment传递参数的方法(spring boot 2.3.3)

    一,thymeleaf如何给fragment传递参数? 1,如果是全局的参数,可以用interceptor中传递 非全局参数,可以从controller中传递 2,引用片断时也可以传递参数 说明:刘宏 ...

  6. linux(centos8):awk在系统运维中的常用例子

    一,awk的作用 1,用途 AWK是一种处理文本文件的语言, 是一个强大的文本分析工具 2,awk和sed的区别 awk适合按列(域)操作, sed适合按行操作 awk适合对文件的读取分析, sed适 ...

  7. Linux下批量kill掉进程

    ps -ef|grep java|grep -v grep|cut -c 9-15|xargs kill -9 管道符"|"用来隔开两个命令,管道符左边命令的输出会作为管道符右边命 ...

  8. 【Flutter 混合开发】与原生通信-MethodChannel

    Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...

  9. css和js实现硬件加速渲染自定义滚动条

    听别人说用CSS的变换来实现渲染有硬件加速的效果,看到很多大网站都开始陆续使用上了,我也来说说怎么做,我这边实现的滚动条有自然滚动效果,看起来比较自然,说的再多不如直接写,让我们开始吧! 我们需要自己 ...

  10. c#封装ActiveX接口实践分析

    ActiveX接口 是一个开放的集成平台,为开发人员.用户和 Web生产商提供了一个快速而简便的在 Internet 和 Intranet 创建程序集成和内容的方法. 使用 ActiveX, 可轻松方 ...