openVswitch(OVS)源代码分析之工作流程(key值得提取)

        转载请注明转载地址,原文地址为:http://blog.csdn.net/yuzhihui_no1/article/details/39481745

        其实想了很久要不要去分析下key值得提取,因为key值的提取是比较简单的,而且没多大实用。因为你不可能去修改key的结构,也不可能去修改key值得提取函数(当然了除非你想重构openVswitch整个项目),更不可能在key提取函数中添加自己的代码。因此对于分析key值没有多大的实用性。但我依然去简单分析key值得提取函数,有两个原因:第一、key值作为数据结构在openVswitch中是非常重要的,后期的一些流表查询和匹配都要用到key值;第二、想借机复习下内核网络协议栈的各层协议信息;

        首先来看下各层协议的协议信息:

        第一、二层帧头信息

struct ethhdr {
	unsigned char	h_dest[ETH_ALEN];	/*目标Mac地址 6个字节*/
	unsigned char	h_source[ETH_ALEN];	/*源Mac地址*/
	__be16		h_proto;		/*包的协议类型 IP包:0x800;ARP包:0x806;IPV6:0x86DD*/
} __attribute__((packed));
/*从skb网络数据包中获取到帧头*/
static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
{
	return (struct ethhdr *)skb_mac_header(skb);
}
        第二、三层网络层IP头信息

/*IPV4头结构体*/
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
	__u8	ihl:4, // 报文头部长度
		version:4; // 版本IPv4
#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;   // 协议类型 TCP:6;UDP:17
	__sum16	check;		// 报头校验和
	__be32	saddr;	    // 源IP地址
	__be32	daddr;		// 目的IP地址
	/*The options start here. */
};

#ifdef __KERNEL__
#include <linux/skbuff.h>
/*通过数据包skb获取到IP头部结构体指针*/
static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
{
	return (struct iphdr *)skb_network_header(skb);
}
/*通过数据包skb获取到二层帧头结构体指针*/
static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
{
	return (struct iphdr *)skb_transport_header(skb);
}
        第三、ARP协议头信息

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)操作,请求:1;应答:2;*/

#if 0 //下面被注释掉了,使用时要自己定义结构体
	 /*
	  *	 Ethernet looks like this : This bit is variable sized however...
	  */
	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address源Mac	*/
	unsigned char		ar_sip[4];		/* sender IP address源IP		*/
	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address目的Mac	*/
	unsigned char		ar_tip[4];		/* target IP address	目的IP	*/
#endif

};
        对于传输层协议信息TCP/UDP协议头信息比较多,这里就不分析了。下面直接来看key值提取代码:

int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key)
{
	int error;
	struct ethhdr *eth; //帧头协议结构指针

	memset(key, 0, sizeof(*key));// 初始化key为0

	key->phy.priority = skb->priority;//赋值skb数据包的优先级
	if (OVS_CB(skb)->tun_key)
		memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
	key->phy.in_port = in_port;// 端口成员的设置
	key->phy.skb_mark = skb_get_mark(skb);//默认为0

	skb_reset_mac_header(skb);//该函数的实现skb->mac_header = skb->data;

	/* Link layer.  We are guaranteed to have at least the 14 byte Ethernet
	 * header in the linear data area.
	 */
	eth = eth_hdr(skb); //获取到以太网帧头信息
	memcpy(key->eth.src, eth->h_source, ETH_ALEN);// 源地址成员赋值
	memcpy(key->eth.dst, eth->h_dest, ETH_ALEN);// 目的地址成员赋值

	__skb_pull(skb, 2 * ETH_ALEN);//这是移动skb结构中指针

	if (vlan_tx_tag_present(skb))// 数据包的类型判断设置
		key->eth.tci = htons(vlan_get_tci(skb));
	else if (eth->h_proto == htons(ETH_P_8021Q))//  协议类型设置
		if (unlikely(parse_vlan(skb, key)))
			return -ENOMEM;

	key->eth.type = parse_ethertype(skb);//包的类型设置,即是IP包还是ARP包
	if (unlikely(key->eth.type == htons(0)))
		return -ENOMEM;

	skb_reset_network_header(skb);// 函数实现:skb->nh.raw = skb->data;
	__skb_push(skb, skb->data - skb_mac_header(skb));// 移动skb中的指针

	/* Network layer. */
	// 判断是否是邋IP数据包,如果是则设置IP相关字段
	if (key->eth.type == htons(ETH_P_IP)) {
		struct iphdr *nh;//设置IP协议头信息结构体指针
		__be16 offset;// 大端格式short类型变量

		error = check_iphdr(skb);// 检测IP协议头信息
		if (unlikely(error)) {
			if (error == -EINVAL) {
				skb->transport_header = skb->network_header;
				error = 0;
			}
			return error;
		}

		nh = ip_hdr(skb);// 函数实现:return (struct iphdr *)skb_network_header(skb);
		// 下面就是IP协议头的一些字段的赋值
		key->ipv4.addr.src = nh->saddr;
		key->ipv4.addr.dst = nh->daddr;

		key->ip.proto = nh->protocol;
		key->ip.tos = nh->tos;
		key->ip.ttl = nh->ttl;

		offset = nh->frag_off & htons(IP_OFFSET);
		if (offset) {
			key->ip.frag = OVS_FRAG_TYPE_LATER;
			return 0;
		}
		if (nh->frag_off & htons(IP_MF) ||
			 skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
			key->ip.frag = OVS_FRAG_TYPE_FIRST;

		/* Transport layer. */
		if (key->ip.proto == IPPROTO_TCP) {
			if (tcphdr_ok(skb)) {
				struct tcphdr *tcp = tcp_hdr(skb);
				key->ipv4.tp.src = tcp->source;
				key->ipv4.tp.dst = tcp->dest;
			}
		} else if (key->ip.proto == IPPROTO_UDP) {
			if (udphdr_ok(skb)) {
				struct udphdr *udp = udp_hdr(skb);
				key->ipv4.tp.src = udp->source;
				key->ipv4.tp.dst = udp->dest;
			}
		} else if (key->ip.proto == IPPROTO_ICMP) {
			if (icmphdr_ok(skb)) {
				struct icmphdr *icmp = icmp_hdr(skb);
				/* The ICMP type and code fields use the 16-bit
				 * transport port fields, so we need to store
				 * them in 16-bit network byte order. */
				key->ipv4.tp.src = htons(icmp->type);
				key->ipv4.tp.dst = htons(icmp->code);
			}
		}
      // 判断是否是ARP数据包,设置ARP数据包字段
	} else if ((key->eth.type == htons(ETH_P_ARP) ||
		   key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) {
		struct arp_eth_header *arp; // 定义ARP协议头结构体指针


		arp = (struct arp_eth_header *)skb_network_header(skb);// return skb->nh.raw;
	// 下面就是一些ARP数据包字段的设置
		if (arp->ar_hrd == htons(ARPHRD_ETHER)
				&& arp->ar_pro == htons(ETH_P_IP)
				&& arp->ar_hln == ETH_ALEN
				&& arp->ar_pln == 4) {

			/* We only match on the lower 8 bits of the opcode. */
			if (ntohs(arp->ar_op) <= 0xff)
				key->ip.proto = ntohs(arp->ar_op);
			memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
			memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
			memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
			memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
		}
		//判断是否是IPV6数据包,设置IPV6数据包字段
	} else if (key->eth.type == htons(ETH_P_IPV6)) {
		int nh_len;             /* IPv6 Header + Extensions */
	// IPV6就不分析了
		nh_len = parse_ipv6hdr(skb, key);
		if (unlikely(nh_len < 0)) {
			if (nh_len == -EINVAL) {
				skb->transport_header = skb->network_header;
				error = 0;
			} else {
				error = nh_len;
			}
			return error;
		}

		if (key->ip.frag == OVS_FRAG_TYPE_LATER)
			return 0;
		if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
			key->ip.frag = OVS_FRAG_TYPE_FIRST;

		/* Transport layer. */
		if (key->ip.proto == NEXTHDR_TCP) {
			if (tcphdr_ok(skb)) {
				struct tcphdr *tcp = tcp_hdr(skb);
				key->ipv6.tp.src = tcp->source;
				key->ipv6.tp.dst = tcp->dest;
			}
		} else if (key->ip.proto == NEXTHDR_UDP) {
			if (udphdr_ok(skb)) {
				struct udphdr *udp = udp_hdr(skb);
				key->ipv6.tp.src = udp->source;
				key->ipv6.tp.dst = udp->dest;
			}
		} else if (key->ip.proto == NEXTHDR_ICMP) {
			if (icmp6hdr_ok(skb)) {
				error = parse_icmpv6(skb, key, nh_len);
				if (error)
					return error;
			}
		}
	}


	return 0;
}
  • 4
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 2
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

庾志辉

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值