套接字缓存之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. 多测师讲解接口测试 _windows中搭建环境cms_高级讲师肖sir

    eclipse集成开发环境 搭建开发环境需要安装的工具如下 jdk-8u60-windows-x64.exe        jdk eclipse.rar      集成开发框架 mysql-inst ...

  2. 正式班D8

    2020.10.15星期四 正式班D8 一.上节课复习 OSI七层协议 socket socket是对传输层以下的封装 IP+port标识唯一一个基于网络通讯的软件 TCP与UDP TCP:因为在通信 ...

  3. 使用leveldb

    C++引入leveldb 编译安装: git clone --recurse-submodules https://github.com/google/leveldb.git cd leveldb m ...

  4. jquery的实时触发事件(textarea实时获取中文个数)

    jquery的实时触发事件(textarea实时获取中文个数) (2014-09-16 11:49:50) 转载▼ 标签: 实时触发事件 中文个数 onpropertychange oninput o ...

  5. 【ST表】SCOI2016 萌萌哒

    题目内容 洛谷链接 一个长度为\(n\)的大数,用\(S_1S_2S_3...S_n\)表示,其中\(S_i\)表示数的第\(i\)位,\(S_1\)是数的最高位,告诉你一些限制条件,每个条件表示为四 ...

  6. swoole一键协程

    swoole4.x后支持一键协程 加上后,开启一键协程化后,MySQL.Redis.Curl 等操作会变成异步 IO //此行代码后,文件操作,sleep,Mysqli,PDO,streams等都变成 ...

  7. linux(centos8):用uniq去除文本中重复的行(去重)

    一,uniq命令的用途 1, 作用: 从输入文件或标准输入中找到相邻的匹配行, 并写入到输出文件或标准输出 2, 使用时通常会搭配sort使用 说明:刘宏缔的架构森林是一个专注架构的博客,地址:htt ...

  8. centos8平台使用lsof

    一,lsof的用途 lsof,List Open Files 列出当前系统打开文件的工具. 在linux环境下,任何事物都以文件的形式存在, 所以lsof通过文件不仅仅可以访问常规数据,还可以访问网络 ...

  9. 第十二章 Linux三剑客之老三—grep

    一.Linux grep 命令用于查找文件里符合条件的字符串. Linux系统中的grep命令是一种功能强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来.grep全称是Global ...

  10. 技术实操丨HBase 2.X版本的元数据修复及一种数据迁移方式

    摘要:分享一个HBase集群恢复的方法. 背景 在HBase 1.x中,经常会遇到元数据不一致的情况,这个时候使用HBCK的命令,可以快速修复元数据,让集群恢复正常. 另外HBase数据迁移时,大家经 ...