本文分析基於Linux Kernel 3.2.1
幾個月之前做了關於Linux內核版本1.2.13網絡棧的結構框架分析並實現了基於Netfilter的包過濾防火牆,這裡以內核3.2.1內核為例來進一步分析,更全面的分析網絡棧的結構。
更多請查看 Linux內核--網絡內核實現分析
1、先說一下sk_buff結構體
這個結構體是套接字的緩沖區,詳細記錄了一個數據包的組成,時間、網絡設備、各層的首部及首部長度和數據的首尾指針。
下面是他的定義,挺長
- struct sk_buff {
- /* These two members must be first. */
- struct sk_buff *next;
- struct sk_buff *prev;
-
- ktime_t tstamp;
-
- struct sock *sk;
- struct net_device *dev;
-
- /*
- * 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;
- #ifdef CONFIG_XFRM
- struct sec_path *sp;
- #endif
- unsigned int len,
- data_len;
- __u16 mac_len,
- hdr_len;
- union {
- __wsum csum;
- struct {
- __u16 csum_start;
- __u16 csum_offset;
- };
- };
- __u32 priority;
- kmemcheck_bitfield_begin(flags1);
- __u8 local_df:1,
- cloned:1,
- ip_summed:2,
- nohdr:1,
- nfctinfo:3;
- __u8 pkt_type:3,
- fclone:2,
- ipvs_property:1,
- peeked:1,
- nf_trace:1;
- kmemcheck_bitfield_end(flags1);
- __be16 protocol;
-
- void (*destructor)(struct sk_buff *skb);
- #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
- struct nf_conntrack *nfct;
- #endif
- #ifdef NET_SKBUFF_NF_DEFRAG_NEEDED
- struct sk_buff *nfct_reasm;
- #endif
- #ifdef CONFIG_BRIDGE_NETFILTER
- struct nf_bridge_info *nf_bridge;
- #endif
-
- int skb_iif;
- #ifdef CONFIG_NET_SCHED
- __u16 tc_index; /* traffic control index */
- #ifdef CONFIG_NET_CLS_ACT
- __u16 tc_verd; /* traffic control verdict */
- #endif
- #endif
-
- __u32 rxhash;
-
- __u16 queue_mapping;
- kmemcheck_bitfield_begin(flags2);
- #ifdef CONFIG_IPV6_NDISC_NODETYPE
- __u8 ndisc_nodetype:2;
- #endif
- __u8 ooo_okay:1;
- __u8 l4_rxhash:1;
- kmemcheck_bitfield_end(flags2);
-
- /* 0/13 bit hole */
-
- #ifdef CONFIG_NET_DMA
- dma_cookie_t dma_cookie;
- #endif
- #ifdef CONFIG_NETWORK_SECMARK
- __u32 secmark;
- #endif
- union {
- __u32 mark;
- __u32 dropcount;
- };
-
- __u16 vlan_tci;
-
- sk_buff_data_t transport_header;
- sk_buff_data_t network_header;
- sk_buff_data_t mac_header;
- /* 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;
- unsigned int truesize;
- atomic_t users;
- };
可以看到新版本內核中發生了很多變化,其中數據包的首部在早期版本是以union的形式定義的,例如mac_header的定義方式如下:
- union{
- struct ethhdr *ethernet;
- unsigned char *raw;
- }mac;
這裡是以指針的形式給出的
- #ifdef NET_SKBUFF_DATA_USES_OFFSET
- typedef unsigned int sk_buff_data_t;
- #else
- typedef unsigned char *sk_buff_data_t;
- #endif