Linux sk_buff 數據結構


   套接口緩存,主要用途是保存在進程和網絡接口之間相互傳遞的用戶數據以及其餘的一些信息node

   來自Linux-3.14.17源碼api

struct sk_buff {
	/* These two members must be first. */
	struct sk_buff		*next;
	struct sk_buff		*prev;
 
	ktime_t			tstamp;	//接收時間戳或者發送時間戳
 
	struct sock		*sk;		//sk是SKB的宿主傳輸控制塊,在由本地發出或者本地接收時纔有效,使傳輸控制塊與套接口及用戶應用程序相關。
	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);	//SKB信息控制塊,是每層協議的私有信息存儲空間,由每一層協議本身維護並使用,並只在本層有效。
 
	unsigned long		_skb_refdst;	//目的地
#ifdef CONFIG_XFRM
	struct	sec_path	*sp;	//IPSec協議用來跟蹤傳輸的信息
#endif
	unsigned int		len,	//SKB中數據部分長度,包括現行緩存區中的數據長度,data_len以及協議首部長度
				data_len;	//SG類型和FRAGLIST類型聚合分散I/O存儲區中的數據長度
	__u16			mac_len,	//鏈路層報頭的長度。
				hdr_len;	//克隆skb時可寫報頭的長度
	union {			//校驗
		__wsum		csum;
		struct {
			__u16	csum_start;
			__u16	csum_offset;
		};
	};
	__u32			priority;	//數據包隊列的優先級
	kmemcheck_bitfield_begin(flags1);
	__u8			local_df:1,	//表示該SKB在本地容許分片
				cloned:1,	//標記所屬SKB是否已經克隆
				ip_summed:2,	//標記傳輸層校驗和的狀態
				nohdr:1,	//標記payload是否被單獨飲用
				nfctinfo:3;	//skb與鏈接的信息關係
	__u8			pkt_type:3,	//幀類型,是由二層目的地址決定的
				fclone:2,	//當前克隆狀態
				ipvs_property:1,	//SKB是否屬於虛擬服務器
				peeked:1,	//包已經被抓到了,不須要再次抓取了
				nf_trace:1;	//netfilter數據包跟蹤標識
	kmemcheck_bitfield_end(flags1);
	__be16			protocol;	//上層協議,典型的包括IP,IPv6,ARP
 
	void			(*destructor)(struct sk_buff *skb);	//相似析構函數
#if defined( ) || defined(CONFIG_NF_CONNTRACK_MODULE)
	struct nf_conntrack	*nfct;	//相關聯的鏈接(若是有的話)
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
	struct nf_bridge_info	*nf_bridge;	//關於橋接幀保存的數據
#endif
 
	int			skb_iif;	//目的地網絡設備的接口索引
 
	__u32			rxhash;	//包的哈希值
 
	__be16			vlan_proto;	//虛擬局域網封裝協議
	__u16			vlan_tci;	//虛擬局域網標籤控制信息
 
#ifdef CONFIG_NET_SCHED
	__u16			tc_index;	/* traffic control index */	//用於輸入流量控制
#ifdef CONFIG_NET_CLS_ACT
	__u16			tc_verd;	/* traffic control verdict */	//用於輸入流量控制
#endif
#endif
 
	__u16			queue_mapping;	//多設備的隊列映射
	kmemcheck_bitfield_begin(flags2);
#ifdef CONFIG_IPV6_NDISC_NODETYPE
	__u8			ndisc_nodetype:2;	//路由的類型(從鏈路層開始)
#endif
	__u8			pfmemalloc:1;	
	__u8			ooo_okay:1;	//容許socket的映射隊列改變
	__u8			l4_rxhash:1;	//說明rxhash是個四元組的哈希值
	__u8			wifi_acked_valid:1;	//設置wifi_acked
	__u8			wifi_acked:1;	//wifi的幀是否ack
	__u8			no_fcs:1;	//幀校驗序列
	__u8			head_frag:1;
	/* Encapsulation protocol and NIC drivers should use
	 * this flag to indicate to each other if the skb contains
	 * encapsulated packet or not and maybe use the inner packet
	 * headers if needed
	 */
	__u8			encapsulation:1;
	/* 6/8 bit hole (depending on ndisc_nodetype presence) */
	kmemcheck_bitfield_end(flags2);
 
#if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
	union {
		unsigned int	napi_id;	//這個SKB的NAPI的ID
		dma_cookie_t	dma_cookie;	//DMA操做的一個cookie
	};
#endif
#ifdef CONFIG_NETWORK_SECMARK
	__u32			secmark;	//安全標識
#endif
	union {
		__u32		mark;	//通用分組標記
		__u32		dropcount;	//sk_receive_queue溢出的數量
		__u32		reserved_tailroom;	//
	};
 
	__be16			inner_protocol;	//封裝的協議
	__u16			inner_transport_header;	//封裝的內部傳輸報頭
	__u16			inner_network_header;	//封裝的網絡層報頭
	__u16			inner_mac_header;	//封裝的鏈路層報頭
	__u16			transport_header;	//傳輸層報頭
	__u16			network_header;	//網絡層報頭
	__u16			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;	//引用計數,用來標識有多少實體引用了該SKB
};


由下圖能夠看出skb在協議棧中的地位緩存

第一層:鏈路層 netif安全

第二層:Ip,Arp服務器

第三層:icmp.igmp,udp,tcpcookie

第四層:skb_queue網絡


//獲取以太網卡頭部app

sturct  eth_hdr  *ehdr=eth_hdr(skb);socket

//獲取arp頭部tcp

sturct  arphdr *arp = arp_hdr(skb);

//獲取IP頭部

struct  iphdr  *iph=ip_hdr(skb);

//獲取UDP頭部

struct udphdr *uh = udp_hdr(skb);

//獲取TCP頭部

struct tcphdr *th = tcp_hdr(skb);



struct ethhdr {
	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
	__be16		h_proto;		/* packet type ID field	*/
} __attribute__((packed));
struct arphdr {
	__be16		ar_hrd;		/* format of hardware address	*/
	__be16		ar_pro;		/* format of protocol address	*/
	unsigned char	ar_hln;		/* length of hardware address	*/
	unsigned char	ar_pln;		/* length of protocol address	*/
	__be16		ar_op;		/* ARP opcode (command)		*/

#if 0
	 /*
	  *	 Ethernet looks like this : This bit is variable sized however...
	  */
	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
	unsigned char		ar_sip[4];		/* sender IP address		*/
	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
	unsigned char		ar_tip[4];		/* target IP address		*/
#endif

};

struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8	ihl:4,
		version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
	__u8	version:4,
  		ihl:4;
#else
#error	"Please fix <asm/byteorder.h>"
#endif
	__u8	tos;
	__be16	tot_len;
	__be16	id;
	__be16	frag_off;
	__u8	ttl;
	__u8	protocol;
	__sum16	check;
	__be32	saddr;
	__be32	daddr;
	/*The options start here. */
};


struct udphdr {
	__be16	source;
	__be16	dest;
	__be16	len;
	__sum16	check;
};


struct tcphdr {
	__be16	source;
	__be16	dest;
	__be32	seq;
	__be32	ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u16	res1:4,
		doff:4,
		fin:1,
		syn:1,
		rst:1,
		psh:1,
		ack:1,
		urg:1,
		ece:1,
		cwr:1;
#elif defined(__BIG_ENDIAN_BITFIELD)
	__u16	doff:4,
		res1:4,
		cwr:1,
		ece:1,
		urg:1,
		ack:1,
		psh:1,
		rst:1,
		syn:1,
		fin:1;
#else
#error	"Adjust your <asm/byteorder.h> defines"
#endif	
	__be16	window;
	__sum16	check;
	__be16	urg_ptr;
};
相關文章
相關標籤/搜索