Linux 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

25091706_Dmz1.jpg


//获取以太网卡头部

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;
};


转载于:https://my.oschina.net/manmao/blog/607962

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值