其实想了很久要不要去分析下key值的提取,因为key值的提取是比较简单的,而且没多大实用。因为你不可能去修改key的结构,也不可能去修改key值的提取函数(当然了除非你想重构Open vSwitch整个项目),更不可能在key提取函数中添加自己的代码。因此对于分析key值没有多大的实用性。但我依然去简单分析key值提取函数,有两个原因:第一、key值作为数据结构在Open vSwitch中是非常重要的,后期的一些流表查询和匹配都要用到key值;第二、想借机复习下内核网络协议栈的各层协议信息。首先来看下各层协议的协议信息。
第一、二层帧头信息
1 2 3 4 5 6 7 8 9 10 |
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头信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/*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协议头信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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值提取代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
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; } |
转载自:CSDN,http://blog.csdn.net/yuzhihui_no1/article/details/39481745