skb各层结构体

1、skb结构体

skb定义

linux/skbuff.h

重要的数据成员包括(暂不分析,完整结构见文章最后的附录)

struct sk_buff {
	...
	__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;
	...
}

1.1 以太网(mac)头部

1.1.1 结构及获取

linux/if_ether.h中,定义其结构为:

struct ethhdr {
    unsigned char   h_dest[ETH_ALEN];   /* destination eth addr */ //目的mac地址
    unsigned char   h_source[ETH_ALEN]; /* source ether addr    */ //源mac地址
    __be16      h_proto;        /* packet type ID field */
} __attribute__((packed));
#define ETH_ALEN    6       /* Octets in one ethernet addr   */

常见协议h_proto类型有:

#define ETH_P_IP    0x0800      /* Internet Protocol packet */
#define ETH_P_ARP   0x0806      /* Address Resolution packet    */
#define ETH_P_8021Q 0x8100      /* 802.1Q VLAN Extended Header  */
#define ETH_P_IPV6  0x86DD      /* IPv6 over bluebook       */

获取方式(仅列举常用):

struct ethhdr * peth_hdr = NULL;
peth_hdr = eth_hdr(skb);

打印mac地址方法:

printk("dst_addr %pM src_addr %pM \n", peth_hdr->h_dest, peth_hdr->h_source);
1.1.2 vlan头部

linux/if_vlan.h 中定义

/**
 *  struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr)
 *  @h_dest: destination ethernet address
 *  @h_source: source ethernet address
 *  @h_vlan_proto: ethernet protocol
 *  @h_vlan_TCI: priority and VLAN ID
 *  @h_vlan_encapsulated_proto: packet type ID or len
 */
struct vlan_ethhdr {
    unsigned char   h_dest[ETH_ALEN];
    unsigned char   h_source[ETH_ALEN];
    __be16      h_vlan_proto;
    __be16      h_vlan_TCI;
    __be16      h_vlan_encapsulated_proto;
    //这个后面紧跟着__be16      h_proto;        /* packet type ID field */
};

只是为了擦除vlan头部,可以如下操作:

if (peth_hdr->h_proto == htons(ETH_P_8021Q))
	peth_hdr = (struct ethhdr *)((unsigned char*)peth_hdr + VLAN_HLEN);
#define VLAN_HLEN   4       /* The additional bytes required by VLAN
                     * (in addition to the Ethernet header)
                     */

之后重新判断h_proto即可,此时不能获取h_dest、h_source,因为这两个值已经不对了。

1.1.3 ip头部

判断是否为IP(ipv4)协议

struct iphdr * pip_hdr = NULL;
if(peth_hdr->h_proto == htons(ETH_P_IP)) {
	pip_hdr = (struct iphdr *) ((unsigned char*)peth_hdr  + sizeof(struct ethhdr));
}

linux/ip.h中定义:

struct iphdr {
    __u8    version:4,
        ihl:4;
    __u8    tos;
    __be16  tot_len;
    __be16  id; 
    __be16  frag_off;
    __u8    ttl; //生存时间
    __u8    protocol; //协议类型
    __sum16 check;
    __be32  saddr; //源Ip
    __be32  daddr; //目的IP
    /*The options start here. */
};

ip打印方法:

u32 saddr, daddr;
saddr = ntohl(pip_hdr->saddr);
daddr = ntohl(pip_hdr->daddr);
printk("sa %pI4h da %pI4h\n", &saddr, &daddr);

常见的ip protocol协议类型

IPPROTO_ICMP = 1,     /* Internet Control Message Protocol    */
IPPROTO_IGMP = 2,     /* Internet Group Management Protocol   */
IPPROTO_TCP = 6,      /* Transmission Control Protocol    */
IPPROTO_UDP = 17,     /* User Datagram Protocol       */
1.1.4 ICMP头部

ICMP协议属于IP协议分支,一般ping指令发出的包均为icmp协议包,linux/icmp.h中:

struct icmphdr {
  __u8      type; //icmp报文类型
  __u8      code;
  __sum16   checksum;
  union {
    struct {
        __be16  id; 
        __be16  sequence; //序列号
    } echo;
    __be32  gateway;
    struct {
        __be16  __unused;
        __be16  mtu;
    } frag;
    __u8    reserved[4];
  } un; 
};

icmp type常见报文类型

#define ICMP_ECHOREPLY      0   /* Echo Reply           */ //ping回复
#define ICMP_DEST_UNREACH   3   /* Destination Unreachable  */ //ping不通时
#define ICMP_ECHO       8   /* Echo Request         */ //ping请求
1.1.5 IGMP头部

IGMP协议属于IP协议分支,用于路由器间的组播协议,linux/igmp.h中:

struct igmphdr {
    __u8 type;
    __u8 code;      /* For newer IGMP */
    __sum16 csum;
    __be32 group;
};

参考相关协议,暂不过多分析

1.1.6 TCP/UDP头部

暂不分析,后续需要使用时再补充

附录

sk_buff完整结构
struct sk_buff {
	union {
		struct {
			/* These two members must be first. */
			struct sk_buff		*next;
			struct sk_buff		*prev;

			union {
				struct net_device	*dev;
				/* Some protocols might use this space to store information,
				 * while device pointer would be NULL.
				 * UDP receive path is one user.
				 */
				unsigned long		dev_scratch;
			};
		};
		struct rb_node		rbnode; /* used in netem, ip4 defrag, and tcp stack */
		struct list_head	list;
	};

	union {
		struct sock		*sk;
		int			ip_defrag_offset;
	};

	union {
		ktime_t		tstamp;
		u64		skb_mstamp;
	};
	/*
	 * 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;
	void			(*destructor)(struct sk_buff *skb);
	bool            (*vendor_free)(struct sk_buff *skb, bool force_release);
    __u32           vendor_free_priv[4];
#ifdef CONFIG_XFRM
	struct	sec_path	*sp;
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
	unsigned long		 _nfct;
#endif
#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
	struct nf_bridge_info	*nf_bridge;
#endif
	unsigned int		len,
				data_len;
	__u16			mac_len,
				hdr_len;

	/* Following fields are _not_ copied in __copy_skb_header()
	 * Note that queue_mapping is here mostly to fill a hole.
	 */
	__u16			queue_mapping;

/* if you move cloned around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define CLONED_MASK	(1 << 7)
#else
#define CLONED_MASK	1
#endif
#define CLONED_OFFSET()		offsetof(struct sk_buff, __cloned_offset)

	__u8			__cloned_offset[0];
	__u8			cloned:1,
				nohdr:1,
				fclone:2,
				peeked:1,
				head_frag:1,
				xmit_more:1,
				pfmemalloc:1;

	/* fields enclosed in headers_start/headers_end are copied
	 * using a single memcpy() in __copy_skb_header()
	 */
	/* private: */
	__u32			headers_start[0];
	/* public: */

/* if you move pkt_type around you also must adapt those constants */
#ifdef __BIG_ENDIAN_BITFIELD
#define PKT_TYPE_MAX	(7 << 5)
#else
#define PKT_TYPE_MAX	7
#endif
#define PKT_TYPE_OFFSET()	offsetof(struct sk_buff, __pkt_type_offset)

	__u8			__pkt_type_offset[0];
	__u8			pkt_type:3;
	__u8			ignore_df:1;
	__u8			nf_trace:1;
	__u8			ip_summed:2;
	__u8			ooo_okay:1;

	__u8			l4_hash:1;
	__u8			sw_hash:1;
	__u8			wifi_acked_valid:1;
	__u8			wifi_acked:1;
	__u8			no_fcs:1;
	/* Indicates the inner headers are valid in the skbuff. */
	__u8			encapsulation:1;
	__u8			encap_hdr_csum:1;
	__u8			csum_valid:1;

	__u8			csum_complete_sw:1;
	__u8			csum_level:2;
	__u8			csum_not_inet:1;
	__u8			dst_pending_confirm:1;
#ifdef CONFIG_IPV6_NDISC_NODETYPE
	__u8			ndisc_nodetype:2;
#endif
	__u8			ipvs_property:1;

	__u8			inner_protocol_type:1;
	__u8			remcsum_offload:1;
#ifdef CONFIG_NET_SWITCHDEV
	__u8			offload_fwd_mark:1;
#endif
#ifdef CONFIG_NET_CLS_ACT
	__u8			tc_skip_classify:1;
	__u8			tc_at_ingress:1;
	__u8			tc_redirected:1;
	__u8			tc_from_ingress:1;
#endif
	__u8			gro_skip:1;

#ifdef CONFIG_NET_SCHED
	__u16			tc_index;	/* traffic control index */
#endif

	union {
		__wsum		csum;
		struct {
			__u16	csum_start;
			__u16	csum_offset;
		};
	};
	__u32			priority;
	int			skb_iif;
	__u32			hash;
	__be16			vlan_proto;
	__u16			vlan_tci;
#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS)
	union {
		unsigned int	napi_id;
		unsigned int	sender_cpu;
	};
#endif
#ifdef CONFIG_NETWORK_SECMARK
	__u32		secmark;
#endif

	union {
		__u32		mark;
		__u32		reserved_tailroom;
	};

	union {
		__be16		inner_protocol;
		__u8		inner_ipproto;
	};

	__u16			inner_transport_header;
	__u16			inner_network_header;
	__u16			inner_mac_header;

	__be16			protocol;
	__u16			transport_header;
	__u16			network_header;
	__u16			mac_header;

	/* private: */
	__u32			headers_end[0];
	/* public: */

	/* 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;
	refcount_t		users;
};
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值