Chinaunix首页 | 论坛 | 博客
  • 博客访问: 433215
  • 博文数量: 185
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 681
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-06 21:45
个人简介

为梦而战

文章分类

全部博文(185)

文章存档

2016年(3)

2015年(103)

2014年(79)

我的朋友

分类: LINUX

2015-04-02 13:11:34

 前面已经把分析openVswitch源代码的基础(openVswitch(OVS)源代码分析之数据结构)写得非常清楚了,虽然访问的人比较少,也因此让我看到了一个现象:第一篇,openVswitch(OVS)源代码分析之简介其实就是介绍了下有关于云计算现状和openVswitch的各个组成模块,还有笼统的介绍了下其工作流程,个人感觉对于学习openVswitch源代码来说没有多大含金量。云计算现状是根据公司发展得到的个人体会,对学习openVswitch源代码其实没什么帮助;openVswitch各个组成模块到网上一搜一大堆,更别说什么含金量了;最后唯一一点还算过的去的就是openVswitch工作流程图,对从宏观方面来了解整个openVswitch来说还算是有点帮助的。但整体感觉对于学openVswitch源代码没有多少实质性的帮助,可是访问它的人就比较多。相反,第二篇,openVswitch(OVS)源代码分析之数据结构分析了整个openVswitch源代码中涉及到的主要数据结构,这可是花了我不少精力。它也是分析整个源代码的重要基础,更或者说可以把它当做分析openVswitch源代码的字典工具。可是访问它的人数却是少的可怜,为什么会这样呢?

        网上有很多blog写有关于openVswitch的,但是绝大部分只是介绍openVswitch以及怎么安装配置它,或者是一些命令的解释。对于源代码的分析是非常少的,至少我开始学习openVswitch时在网上搜资料那会是这样的。因此对于一个开始接触学习openVswitch源代码的初学者来说是非常困难的,什么资料都没有(当然官网上还是有些资料得,如果你英文够好,看官网的资料也是个不错的选择),只得从头开始去分析,可是要想想openVswitch是由一个世界级的杰出团队花几年的时间设计而成的,如果要从零开始学习分析它,要到猴年马月。所幸的是我开始学的时候,公司前辈们提供了些学习心得以及结构资料,所以在此我也把自己的学习心得和一些理解和大家分享。如有不正确之处,望大家指正,谢谢!!!

        言归正传,基础已经学习过了,下面来正真分析下openVswitch的工作流程源代码。

        首先是数据包的接受函数,这是在加载网卡时把网卡绑定到openVswitch端口上(ovs-vsctl add-port br0 eth0),绑定后每当有数据包过来时,都会调用该函数,把数据包传送给这个函数去处理。而不是像开始那样(未绑定前)把数据包往内核网络协议栈中发送,让内核协议栈去处理。openVswitch中数据包接受函数为:void ovs_vport_receive(struct vport *vport, struct sk_buff *skb);函数,该函数所在位置为:datapath/vport.c中。实现如下:

  1. // 数据包接受函数,绑定网卡后,所有数据包都是从这个函数作为入口传入到openVswitch中去处理的,  
  2. // 可以说这是openVswitch的入口点。参数vport:数据包从哪个端口进来的;参数skb:数据包的地址指针  
  3. void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)  
  4. {  
  5.     struct pcpu_tstats *stats; // 其实这个东西一直没弄明白,大概作用是维护CPU的锁状态   
  6.   
  7.     stats = this_cpu_ptr(vport->percpu_stats); // 开始获取到CPU的锁状态,这和linux内核中的自旋锁类似  
  8.     u64_stats_update_begin(&stats->syncp); // 开始上锁  
  9.     stats->rx_packets++; // 统计数据包的个数  
  10.     stats->rx_bytes += skb->len; // 记录数据包中数据的大小  
  11.     u64_stats_update_end(&stats->syncp);// 结束锁状态  
  12.   
  13.     if (!(vport->ops->flags & VPORT_F_TUN_ID)) // 这是种状态处理  
  14.         OVS_CB(skb)->tun_key = NULL;  
  15.       
  16. // 其实呢这个函数中下面这行代码才是关键,如果不是研究openVswitch而是为了工作,个人觉得没必要(估计也不可能)  
  17. // 去弄清楚每条代码的作用。只要知道大概是什么意思,关键代码有什么作用,如果要添加自己的代码时,该往哪个地方添加就可以了。  
  18. // 下面这行代码是处理数据包的函数调用,是整个openVswitch的核心部分,传入的参数和接受数据包函数是一样的。  
  19.     ovs_dp_process_received_packet(vport, skb);  
  20. }  

        俗话说有接必有还,有进必有出嘛。上面的是数据包进入openVswitch的函数,那一定有其对应的出openVswitch的函数。数据包进入openVswitch后会调用函数ovs_dp_process_received_packet(vport,skb);对数据包进行处理,到后期会分析到,这个函数对数据包进行流表的匹配,然后执行相应的action。其中action动作会操作对数据包进行一些修改,然后再把数据包发送出去,这时就会调用vport.c中的数据包发送函数: ovs_vport_send(struct vport *vport, struct sk_buff *skb);来把数据包发送到端口绑定的网卡设备上去,然后网卡驱动就好把数据包中的数据发送出去。当然也有些action会把数据包直接向上层应用发送。下面来分析下数据包发送函数的实现,函数所在位置为:datapath/vport.c中。


  1. // 这是数据包发送函数。参数vport:指定由哪个端口发送出去;参数skb:指定把哪个数据包发送出去  
  2. int ovs_vport_send(struct vport *vport, struct sk_buff *skb)  
  3. {  
  4. // 这是我自己加的代码,为了过滤掉ARP数据包。这里额外的插一句,不管在什么源代码中添加自己的代码时  
  5. // 都要在代码开头处做上自己的标识,因为这样不仅便于自己修改和调试、维护,而且也让其他人便于理解  
  6.        /*===========yuzhihui:==============*/  
  7.     if (0x806 == ntohs(skb->protocol)) {  
  8.           arp_proc_send(vport,skb);// 自定义了一个函数处理了ARP数据包  
  9.     }  
  10.     // 在前篇数据结构中讲了ops是vport结构中的一些操作函数的函数指针集合结构体  
  11.         // 所以vport->ops->send()是函数指针来调用函数,把数据包发送出去  
  12.     int sent = vport->ops->send(vport, skb);  
  13.   
  14.     if (likely(sent)) { // 定义了一个判断宏likely(),如果发送成功执行下面  
  15.         struct pcpu_tstats *stats; // 下面的这些代码是不是觉得非常眼熟,没错就是接受函数中的那些代码  
  16.   
  17.         stats = this_cpu_ptr(vport->percpu_stats);  
  18.   
  19.         u64_stats_update_begin(&stats->syncp);  
  20.         stats->tx_packets++;  
  21.         stats->tx_bytes += sent;  
  22.         u64_stats_update_end(&stats->syncp);  
  23.     }  
  24.     return sent; // 返回的sent是已经发送成功的数据长度  
  25. }  


        这两个函数就是openVswitch中收发数据包函数了,对这两个函数没有完全去分析它的所有代码,这也不是我的本意,我只是想让初学者知道这是数据包进入和离开openVswitch的函数。其实知道了这个是非常有用的,因为不管你是什么数据包,只要是到该主机的(当然了包括主机内的各种虚拟机及服务器),全部都会经过这两个函数(对于接受的数据时一定要进过接受函数的,但是发送数据包有时候到不了发送函数的),那么要对数据包进行怎么样的操作那就全看你想要什么操作了。

        在这两个函数中对数据包操作举例:

        数据包接受函数中操作:如果你要阻断和某个IP主机间的通信(或者对某个IP主机数据包进行特殊处理),那么你可以在数据进入openVswitch的入口函数(ovs_vport_receive(struct vport *vport, struct sk_buff *skb);)中进行处理,判断数据包中提取到的IP对比,如果是指定IP则把这个数据包直接销毁掉(也可以自己定义函数做些特殊操作)。这样就可以对整个数据进行控制。

        数据包发送函数中操作:就像上面的函数中我自己写的那些代码一样,提取数据包中数据包类型进行判断,当判断如果是ARP数据包时,则调用我自定义的 arp_proc_send(vport,skb);函数进行去处理,而不是贸然的直接把它发送出去,因为你不知道该数据包发送的端口是什么类型的。如果是公网IP端口,那么就在自定义函数中直接把这个数据包掐死掉(ARP数据包是在局域网内作用的,就算发到公网上也会被处理掉的);如果是发送到外层局域网中或者是相连的服务器中,则修改数据包中的目的Mac地址进行洪发;又如果是个ARP请求数据包,则把该数据包修改为应答包,再原路发送回去,等等情况;这些操作控制都是在发送数据包函数中做的手脚。

        以上就是openVswitch(OVS)工作流程中的数据包收发函数,经过大概的分析和应用举例说明,我想对于初学者来说应该知道大概在哪个地方添加自己的代码,实现自己的功能要求了。

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

                                                                                                                                    如有不正确之处,望大家指正,谢谢!!!

阅读(876) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~