{ } ?
通过了eth_type_trans后,skb->data指针指向网络层的头部,在netif_receive_skb里初始化nh.raw和h.raw:
skb->h.raw = skb->nh.raw = skb->data; skb->mac_len = skb->nh.raw - skb->mac.raw; netif_receive_skb ? packet_type->func() ? ip_rcv() ?
如果只是转发,不用处理到L4,只有发给本机的包才需要,在进入L4处理之前,ip_local_deliver_finish会把h.raw初始化为L4的头部: int ihl = skb->nh.iph->ihl*4;
__skb_pull(skb, ihl);
/* Point into the IP datagram, just past the header. */ skb->h.raw = skb->data;
return (struct ethhdr *)skb->mac.raw;
其他相关结构
skb_shared_info
当调用 alloc_skb() 构造 SKB 和 data buffer时,需要的 buffer 大小是这样计算的: data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
除了指定的 size 以外,还包括一个 struct skb_shared_info 结构的空间大小。也就是说,当调用 alloc_skb(size) 要求分配 size 大小的 buffer 的时候,同时还创建了一个 skb_shared_info 。这个结构定义如下: struct skb_shared_info { };
“dataref”:skb的data区域(线性buffer)引用计数,即有多少个skb结构指向这块data区域(skb_clone时++),被分为两部分:高16bits用于描述skb->data中payload部分的引用计数(skb->nohdr = 1时才有效),低16bits用来描述整个skb->data的引用计数,如下: /* We divide dataref into two halves. The higher 16 bits hold references * to the payload part of skb->data. The lower 16 bits hold references to
atomic_t dataref;
unsigned short nr_frags; unsigned short gso_size;
/* Warning: this field is not always filled in (UFO)! */ unsigned short gso_segs; unsigned short gso_type; __be32 ip6_frag_id; struct sk_buff *frag_list; skb_frag_t frags[MAX_SKB_FRAGS];
* the entire skb->data. It is up to the users of the skb to agree on * where the payload starts. *
* All users must obey the rule that the skb->data reference count must be * greater than or equal to the payload reference count. *
* Holding a reference to the payload part means that the user does not * care about modifications to the header part of skb->data. */
#define SKB_DATAREF_SHIFT 16
#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1)
“nr_frags”: “paged_data”计数,最多为MAX_SKB_FRAGS = 65536/PAGE_SIZE + 2(4k的PAGE_SIZE,为18)
“skb_frag_t frags[MAX_SKB_FRAGS]”:用来记录paged_data实际位置,包含page指针,在page中的offset,以及占用的size 。(可以有不同的skb指向同一个page中的不同offset和size,也可以指向相同的,由page里头的_count来代表引用计数) struct skb_frag_struct { };
“gso_size”,“gso_segs”,“gso_type”由“GSO”(Generic Segmentation Offload,或叫“TSO”,即TCP Segmentation Offload)功能使用 enum { };
“frag_list”:分片处理中,记录分片使用。
我们只要把 end 从 char* 转换成skb_shared_info* ,就能访问到这个结构 Linux 提供一个宏来做这种转换:
#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end)) 那么,这个隐藏的结构用意何在?它至少有两个目的: 1、 用于管理 paged data 2、 用于管理分片
SKB_GSO_TCPV4 = 1 << 0, SKB_GSO_UDP = 1 << 1,
/* This indicates the skb is from an untrusted source. */ SKB_GSO_DODGY = 1 << 2,
/* This indicates the tcp segment has CWR set. */ SKB_GSO_TCP_ECN = 1 << 3, SKB_GSO_TCPV6 = 1 << 4, struct page *page; __u16 page_offset; __u16 size;
sk_buff_head和skb队列
协议栈处理中经常用到sk_buff的队列,队列头使用struct sk_buff_head来描述,如下: struct sk_buff_head { };
其中包含一个指示队列长度的qlen,和一个自旋锁lock用于不同的进程同时操作队列时的保护。 一个sk_buff队列如下图:
/* These two members must be first. */ struct sk_buff *next; struct sk_buff *prev; __u32
qlen;
spinlock_t lock;
sk_buff操作
下面对net/core/skbuff.c里调用EXPORT_SYMBOL导出的函数进行较为详细的分析,但仅限于每个函数本身完成的功能,具体调用的位置还得参考协议栈处理其他部分的代码。
EXPORT_SYMBOL(___pskb_trim); EXPORT_SYMBOL(__kfree_skb); EXPORT_SYMBOL(kfree_skb); EXPORT_SYMBOL(__pskb_pull_tail); EXPORT_SYMBOL(__alloc_skb); EXPORT_SYMBOL(__netdev_alloc_skb); EXPORT_SYMBOL(pskb_copy); EXPORT_SYMBOL(pskb_expand_head);
EXPORT_SYMBOL(skb_checksum); EXPORT_SYMBOL(skb_clone);
EXPORT_SYMBOL(skb_clone_fraglist); EXPORT_SYMBOL(skb_copy);
EXPORT_SYMBOL(skb_copy_and_csum_bits); EXPORT_SYMBOL(skb_copy_and_csum_dev); EXPORT_SYMBOL(skb_copy_bits); EXPORT_SYMBOL(skb_copy_expand); EXPORT_SYMBOL(skb_over_panic); EXPORT_SYMBOL(skb_pad);
EXPORT_SYMBOL(skb_realloc_headroom); EXPORT_SYMBOL(skb_under_panic); EXPORT_SYMBOL(skb_dequeue); EXPORT_SYMBOL(skb_dequeue_tail); EXPORT_SYMBOL(skb_insert); EXPORT_SYMBOL(skb_queue_purge); EXPORT_SYMBOL(skb_queue_head); EXPORT_SYMBOL(skb_queue_tail); EXPORT_SYMBOL(skb_unlink); EXPORT_SYMBOL(skb_append); EXPORT_SYMBOL(skb_split);
EXPORT_SYMBOL(skb_prepare_seq_read); EXPORT_SYMBOL(skb_seq_read); EXPORT_SYMBOL(skb_abort_seq_read); EXPORT_SYMBOL(skb_find_text);
EXPORT_SYMBOL(skb_append_datato_frags);
skb分配相关操作
__alloc_skb, alloc_skb,alloc_skb_fclone, __dev_alloc_skb,
__netdev_alloc_skb,sock_alloc_send_pskb, sock_alloc_send_skb, sk_stream_alloc_skb, sk_stream_alloc_pskb, sock_wmalloc等
基本上内核里所有的skb分配都是通过直接调用__alloc_skb或相应的包装函数来完成,下面先对__alloc_skb进行分析,然后再稍微讨论几个包装函数。 1. 输入参数:跟内存分配/相关的暂时不讨论;
a) size:指的是线性buffer的长度,即skb->end - skb->head; b) gfp_mask:allocation_mask,跟内存分配的优先级等相关;
c) fclone:从skbuff_fclone_cache还是skbuff_head_cache分配skb结构,用于快速clone;
d) node:用于分配内存的numa node
2. 具体操作:
a) 分配skb结构本身:根据fclone选择cache,然后把gfp_mask&~__GFP_DMA,得到
skb,分配失败则退出;
b) 分配skb->data线性buffer区:
i. ii. iii.
size = SKB_DATA_ALIGN(size); 根据L1_CACHE_BYTES(X86上为128 bytes)调整大小,补齐为128的整数倍;
kmalloc的内存大小为size + sizeof(struct skb_shared_info) 初始化skb成员变量
1. truesize之前的都置为0;
2. truesize = SKB_DATA_ALIGN(size) + sizeof(struct sk_buff),并不包
含skb_shared_info; 3. users置为1,head/data/tail指向线性buffer的开始;end指向结束; 4. 根据fclone设置skb->fclone,以及对应的兄弟skb及fclone_ref;
iv. skb_shared_info初始化 1. dataref置为1; 2. 其他置为0或NULL;
3. 返回值:skb或data内存分配失败,返回NULL;否则返回创建的sk_buff指针。
常见的__alloc_skb包装函数包括:
? alloc_skb和alloc_fclone_skb:原型如下,一个fclone,另一个不理;numa node
都是-1;
static inline struct sk_buff *alloc_skb(unsigned int size,gfp_t priority) {
return __alloc_skb(size, priority, 0, -1);
}
static inline struct sk_buff *alloc_skb_fclone(unsigned int size,gfp_t priority) { } ?
dev_alloc_skb和__dev_alloc_skb:一般是网卡驱动分配用于接收缓存的skb,length会加上NET_SKB_PAD,调用完alloc_skb后,会通过skb_reserve在线性buffer的头部保留一块长度为NET_SKB_PAD的区域,有关NET_SKB_PAD和NET_IP_ALIGN的说明,可以参见内核代码中的注释; /*
* CPUs often take a performance hit when accessing unaligned memory * locations. The actual performance hit varies, it can be small if the * hardware handles it or large if we have to take an exception and fix it * in software. *
* Since an ethernet header is 14 bytes network drivers often end up with * the IP header at an unaligned offset. The IP header can be aligned by * shifting the start of the packet by 2 bytes. Drivers should do this * with:
*
* skb_reserve(NET_IP_ALIGN); *
return __alloc_skb(size, priority, 1, -1);
百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库sk_buff详解(3)在线全文阅读。
相关推荐: