首页
登录 | 注册

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

        原文地址为:http://blog.csdn.net/yuzhihui_no1/article/details/39481745

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

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

        第一、二层帧头信息
      

  1. struct ethhdr {
  2.     unsigned char    h_dest[ETH_ALEN];    /*目标Mac地址 6个字节*/
  3.     unsigned char    h_source[ETH_ALEN];    /*源Mac地址*/
  4.     __be16        h_proto;        /*包的协议类型 IP包:0x800;ARP包:0x806;IPV6:0x86DD*/
  5. } __attribute__((packed));
  6. /*从skb网络数据包中获取到帧头*/
  7. static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)
  8. {
  9.     return (struct ethhdr *)skb_mac_header(skb);
  10. }
      第二、三层网络层IP头信息
  
  1. /*IPV4头结构体*/
  2. struct iphdr {
  3. #if defined(__LITTLE_ENDIAN_BITFIELD)
  4. __u8    ihl:4, // 报文头部长度
  5. version:4; // 版本IPv4
  6. #elif defined (__BIG_ENDIAN_BITFIELD)
  7. __u8    version:4,
  8.   ihl:4;
  9. #else
  10. #error    "Please fix "
  11. #endif
  12. __u8    tos; // 服务类型
  13. __be16    tot_len; // 报文总长度
  14. __be16    id; // 标志符
  15. __be16    frag_off; // 片偏移量
  16. __u8    ttl;     // 生存时间
  17. __u8    protocol; // 协议类型 TCP:6;UDP:17
  18. __sum16    check;     // 报头校验和
  19. __be32    saddr;     // 源IP地址
  20. __be32    daddr;     // 目的IP地址
  21. /*The options start here. */
  22. };


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

  1. struct arphdr
  2. {
  3.     __be16        ar_hrd;        /* format of hardware address硬件类型    */
  4.     __be16        ar_pro;        /* format of protocol address协议类型    */
  5.     unsigned char    ar_hln;        /* length of hardware address硬件长度    */
  6.     unsigned char    ar_pln;        /* length of protocol address协议长度    */
  7.     __be16        ar_op;        /* ARP opcode (command)操作,请求:1;应答:2;*/

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

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

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

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

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

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

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

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

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

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

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

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

  34.         error = check_iphdr(skb);// 检测IP协议头信息
  35.         if (unlikely(error)) {
  36.             if (error == -EINVAL) {
  37.                 skb->transport_header = skb->network_header;
  38.                 error = 0;
  39.             }
  40.             return error;
  41.         }

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

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

  49.         offset = nh->frag_off & htons(IP_OFFSET);
  50.         if (offset) {
  51.             key->ip.frag = OVS_FRAG_TYPE_LATER;
  52.             return 0;
  53.         }
  54.         if (nh->frag_off & htons(IP_MF) ||
  55.              skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
  56.             key->ip.frag = OVS_FRAG_TYPE_FIRST;

  57.         /* Transport layer. */
  58.         if (key->ip.proto == IPPROTO_TCP) {
  59.             if (tcphdr_ok(skb)) {
  60.                 struct tcphdr *tcp = tcp_hdr(skb);
  61.                 key->ipv4.tp.src = tcp->source;
  62.                 key->ipv4.tp.dst = tcp->dest;
  63.             }
  64.         } else if (key->ip.proto == IPPROTO_UDP) {
  65.             if (udphdr_ok(skb)) {
  66.                 struct udphdr *udp = udp_hdr(skb);
  67.                 key->ipv4.tp.src = udp->source;
  68.                 key->ipv4.tp.dst = udp->dest;
  69.             }
  70.         } else if (key->ip.proto == IPPROTO_ICMP) {
  71.             if (icmphdr_ok(skb)) {
  72.                 struct icmphdr *icmp = icmp_hdr(skb);
  73.                 /* The ICMP type and code fields use the 16-bit
  74.                  * transport port fields, so we need to store
  75.                  * them in 16-bit network byte order. */
  76.                 key->ipv4.tp.src = htons(icmp->type);
  77.                 key->ipv4.tp.dst = htons(icmp->code);
  78.             }
  79.         }
  80.       // 判断是否是ARP数据包,设置ARP数据包字段
  81.     } else if ((key->eth.type == htons(ETH_P_ARP) ||
  82.          key->eth.type == htons(ETH_P_RARP)) && arphdr_ok(skb)) {
  83.         struct arp_eth_header *arp; // 定义ARP协议头结构体指针


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

  90.             /* We only match on the lower 8 bits of the opcode. */
  91.             if (ntohs(arp->ar_op) <= 0xff)
  92.                 key->ip.proto = ntohs(arp->ar_op);
  93.             memcpy(&key->ipv4.addr.src, arp->ar_sip, sizeof(key->ipv4.addr.src));
  94.             memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
  95.             memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
  96.             memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
  97.         }
  98.         //判断是否是IPV6数据包,设置IPV6数据包字段
  99.     } else if (key->eth.type == htons(ETH_P_IPV6)) {
  100.         int nh_len; /* IPv6 Header + Extensions */
  101.     // IPV6就不分析了
  102.         nh_len = parse_ipv6hdr(skb, key);
  103.         if (unlikely(nh_len < 0)) {
  104.             if (nh_len == -EINVAL) {
  105.                 skb->transport_header = skb->network_header;
  106.                 error = 0;
  107.             } else {
  108.                 error = nh_len;
  109.             }
  110.             return error;
  111.         }

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

  116.         /* Transport layer. */
  117.         if (key->ip.proto == NEXTHDR_TCP) {
  118.             if (tcphdr_ok(skb)) {
  119.                 struct tcphdr *tcp = tcp_hdr(skb);
  120.                 key->ipv6.tp.src = tcp->source;
  121.                 key->ipv6.tp.dst = tcp->dest;
  122.             }
  123.         } else if (key->ip.proto == NEXTHDR_UDP) {
  124.             if (udphdr_ok(skb)) {
  125.                 struct udphdr *udp = udp_hdr(skb);
  126.                 key->ipv6.tp.src = udp->source;
  127.                 key->ipv6.tp.dst = udp->dest;
  128.             }
  129.         } else if (key->ip.proto == NEXTHDR_ICMP) {
  130.             if (icmp6hdr_ok(skb)) {
  131.                 error = parse_icmpv6(skb, key, nh_len);
  132.                 if (error)
  133.                     return error;
  134.             }
  135.         }
  136.     }


  137.     return 0;
  138. }




相关文章

  • 网页含有害信息已被系统自动阻断 该怎么处理
    被阻断的主机:提示:经我司系统检测该网站上存在有害信息,且在我司发出通知以后24小时还未处理,所以现在主机已经被系统自动禁止访问, 若您是网站,可以[点击此处]查看更多细节,也可以登录我司[管理中心-其它项目-非法信息监测]处点击[解除锁定 ...
  • OpenvSwitch完全使用手册
    OpenvSwitch完全使用手册(一)-总览Overview 本文主要参考Overview of functionality and components以及Frequently Asked Questions以及结合自己的理解. 1 什 ...
  • 1. 背景:     一直以为OpenStack的创建快照的操作是在线创建快照(live snapshot), 并且应该是增量的快照,即利用virsh或者qemu的live snapshot来实现的:          virsh  sna ...
  • 竞品分析全览
    前篇:前期准备 1. 竞品选择 1.1 竞品分级 竞品分级是以我们自身的产品为中心,  . 重要竞品, 远高于我们的产品:  . 核心竞品, 高于并且非常有竞争力的产品:  . 一般竞品, 在我们之下或者还不如我的产品. 竞品分级的目的,是 ...
  • [高级内部资料].NET数据批量写入性能分析 第二篇                在上一篇文章中,我们已经讲述了一些铺垫性的知识,那么从本篇开始,就开始正式的研究批量插入性能问题.          首先来看看,我们主要测试那些东西.因为 ...
  • LeaRun.Framework━ .NET快速开发框架 ━ 工作流程组件介绍
    LeaRun.Framework.NET,基于.NET的快速开发框架.整合框架,为企业或个人在.NET环境下快速开发系统提供了强大的支持,开发人员不需要开发系统的基础功能和公共模块,框架自身提供了强大的函数库和开发包,开发人员只须集中精力专 ...

2020 unjeep.com webmaster#unjeep.com
12 q. 0.014 s.
京ICP备10005923号