C sk_buff如何指向sk_buff_头

C sk_buff如何指向sk_buff_头,c,networking,linux-kernel,C,Networking,Linux Kernel,linux内核中的sk_buff数据结构被组织成一个双链接列表,但该列表的最后一个成员和第一个成员指向一个sk_buff_head结构。但是next和prev成员被声明为指向sk_buff的指针,而不是sk_buff_head。这怎么可能 struct sk_buff { struct sk_buff * next; struct sk_buff * prev; struct sk_buff_head * list; struct sock * sk; struct t

linux内核中的
sk_buff
数据结构被组织成一个双链接列表,但该列表的最后一个成员和第一个成员指向一个
sk_buff_head结构
。但是
next
prev
成员被声明为指向
sk_buff
的指针,而不是
sk_buff_head
。这怎么可能

struct sk_buff {
  struct sk_buff  * next;
  struct sk_buff  * prev;
  struct sk_buff_head * list;
  struct sock  * sk;
  struct timeval  stamp;
  struct net_device * dev;
  struct net_device * real_dev;
  union private;
  #endif#ifdef CONFIG_NET_SCHED__u32   tc_index;
  #endif
  unsigned int  truesize;
  atomic_t users;
};  



struct sk_buff_head { 
  /* These two members must be first. */ 
  struct sk_buff * next;  
  struct sk_buff * prev;  
  __ U32 qlen;  
  spinlock_t lock;  
}; 

双链表中的每个sk_buff结构必须能够快速找到整个链表的头部。这就是sk_buff_head结构的目的,它被插入列表的开头。所以,sk_buff_head是一个特殊的sk_buff。指向里面的另一个sk_buff_头是没有任何意义的。我想你会指向整个不同的双链接列表的头,如果下一个和上一个成员是sk_buff_头…
请参见下图了解此概念。


正如大卫·米勒(David Miller)在其著作中所描述的,sku buff_head结构用于将sku buff放置在多个列表中,并使其易于访问:

struct sk_buff {
    /* These two members must be first. */
    struct sk_buff      *next;
    struct sk_buff      *prev;

    struct sk_buff_head *list;
 ...

前两个成员实现列表处理。数据包可以存在于多种列表和队列中。例如,TCP套接字发送队列。第三个成员说数据包在哪个列表上

这很难看,但它可以工作,因为“下一个”和“上一个”在sk_buff和sk_buff_head的同一位置(第一个字段)。列表处理代码知道它实际上可能是任意一种结构,并在必要时强制(强制)它,以维护环中有一个sk_buff_头的指针环。

这显然是可能的。这会让您感到困惑吗?我的意思是
next
prev
被声明为指向
sk_buff\u结构
,但列表的最后一个成员的
next
成员指向
sk_buff\u head结构
。我的意思是,它指向声明的另一个数据结构,所以它使用了一些强制转换吗?但是
struct sk_buff
prev
next
成员被声明为指向
struct sk_buff
的指针,而不是指向
struct sk_buff\u head
。这就像声明一个指向某个数据类型的指针并使用它指向另一个数据类型,它需要一些强制转换操作对吗?下一个和上一个指向sk_buff结构。struct sk_buff有一个名为list的成员,其类型为
struct sk_buff_head*
,它指向列表的头部(sk_buff_head)。图像显示的是
list
成员,但图像显示,对于列表的最后一个成员,他的
next
成员指向
sk_buff_头部
,我的意思是列表的
list
成员和
next
成员都指向头部存储的同一方向,思想
next
list
被声明为指向不同的数据结构。sk_buff和sk_buff_head的前两个成员是相同的,因此它们可以彼此强制转换(以便检索next或prev成员)