您的位置:首页 > 理论基础 > 数据结构算法

Linux sk_buff 数据结构

2016-01-22 00:00 387 查看
摘要: 研究struct sk_buff的作用和方法

套接口缓存,主要用途是保存在进程和网络接口之间相互传递的用户数据以及其他的一些信息

来自Linux-3.14.17源码

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,tcp

第四层:skb_queue



//获取以太网卡头部

sturct eth_hdr *ehdr=eth_hdr(skb);

//获取arp头部

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;
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: