我是靠谱客的博主 秀丽月亮,最近开发中收集的这篇文章主要介绍走进Linux内核网络 报文是什么—sk_buff,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

今天来聊下sk_buff。如果把内核网络协议栈比作一个人,那么sk_buff就是流淌在他体内血管里红血球,它运输养分(数据)走遍全身(协议栈每一层)。一个sk_buff就是一个报文。

报文的表示方式

在协议栈层次模型中,我们提到过,报文在协议栈各层之间穿梭,发送方向不断加上Header,接收方向不断去掉Header。自然而然,我们要设计数据结构去表示在各个层上形态各异的报文

我们可以这么设计IP报文:

struct ip_pdu{
struct ip_hdr ip_hdr;
char* payload;
}

TCP报文呢, 就像下面这样

struct tcp_pdu{
struct tcp_hdr tcp_hdr;
char* payload;
}

然后层与层之间进行报文数据结构的拷贝和转换。

等等!网络协议那么多,难道要每种协议设计一个新的数据结构?!另外,像这样每个报文都要拷贝多次的话效率也太低了吧?!
所以,linux采用的报文层间传递的方式就是一个结构,传递指针,这个结构就是sk_buff, 也就是说, 无论是哪个层次的报文, 在内核中始终都以sk_buff表示(sk_buffsocket buffer的简称)

下面是sk_buff结构的构成(精简后)

<skbuff.h>
typedef unsigned char *sk_buffer_data_t;
struct sk_buff{
struct sock *sk;
struct net_device *dev;
char cb[40];
sk_buff_data_t transport_header;
sk_buff_data_t network_header;
sk_buff_data_t mac_header;
sk_buff_data_t tail;
sk_buff_data_t end;
unsigned char *head;
*data;
}

重点关注最后四个字段,准确的说是四个指针,
skbuff
如上图所示,这四个指针的外面两个限定了一个大的缓冲区,而中间两个则是包裹了有效数据,所谓有效数据便是报文。这么设计的原因就是避免拷贝! 以发送方向为例,我们知道发送过程是一层一层的在报文前方贴Header,因此,既然我们知道随着报文向下传递时,长度会增加。那么我们不如就在最初报文(应用层)的前面预留一定的空间,就可以避免向下传递时还要重新申请内存再拷贝了。

move
上图描述了在接收方向报文上送时的指针移动方向,之前说的去掉Header就是指这个。

控制字段cb是一个很有意思的字段,它是一个杂货间,没有标准的格式,因此可以存放各种数据,最多40个字节。当报文在协议栈中流动时,流到哪一层,哪一层就将自己的私有数据放到这个区域。比如TCP用这个区域储存收到的TCP报文头中的一些字段。

struct tcp_skb_cb{
......
u32 seq;
/* Starting sequence number
*/
u32 end_seq; /* SEQ + FIN + SYN + dalalen */
u32 when;
/* used to compute rtt
*/
u32 flags
/* TCP header flags
*/
}

struct sock *skstruct net_device *dev则分别代表了sk_buff的起点和终点。对于发送方向,报文由应用层产生,自然是通过一个套接字到内核,最终从一个设备发送出去,这时sk是起点,dev是终点。而对于接收方向,报文由一个设备接收,最终被应用层通过一个套接字拿到,这时,这时dev是起点,sk是终点.

总结

  1. 协议栈使用sk_buff表示所有报文,sk_buff在协议栈中传递时以指针传递并且不会拷贝
  2. cb是一个杂货间,每一层都可以使用
  3. skdev是报文的起点和终点,对发送方向和接收方向来说正好相反。

最后

以上就是秀丽月亮为你收集整理的走进Linux内核网络 报文是什么—sk_buff的全部内容,希望文章能够帮你解决走进Linux内核网络 报文是什么—sk_buff所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(27)

评论列表共有 0 条评论

立即
投稿
返回
顶部