前面已经把分析openVswitch源代码的基础([openVswitch(OVS)源代码分析之数据结构](http://blog.csdn.net/yuzhihui_no1/article/details/39188373))写得非常清楚了,虽然访问的人比较少,也因此让我看到了一个现象:第一篇,[openVswitch(OVS)源代码分析之简介](http://blog.csdn.net/yuzhihui_no1/article/details/39161515)其实就是介绍了下有关于云计算现状和openVswitch的各个组成模块,还有笼统的介绍了下其工作流程,个人感觉对于学习openVswitch源代码来说没有多大含金量。云计算现状是根据公司发展得到的个人体会,对学习openVswitch源代码其实没什么帮助;openVswitch各个组成模块到网上一搜一大堆,更别说什么含金量了;最后唯一一点还算过的去的就是openVswitch工作流程图,对从宏观方面来了解整个openVswitch来说还算是有点帮助的。但整体感觉对于学openVswitch源代码没有多少实质性的帮助,可是访问它的人就比较多。相反,第二篇,[openVswitch(OVS)源代码分析之数据结构](http://blog.csdn.net/yuzhihui_no1/article/details/39188373)分析了整个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中。实现如下:
~~~
// 数据包接受函数,绑定网卡后,所有数据包都是从这个函数作为入口传入到openVswitch中去处理的,
// 可以说这是openVswitch的入口点。参数vport:数据包从哪个端口进来的;参数skb:数据包的地址指针
void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
{
struct pcpu_tstats *stats; // 其实这个东西一直没弄明白,大概作用是维护CPU的锁状态
stats = this_cpu_ptr(vport->percpu_stats); // 开始获取到CPU的锁状态,这和linux内核中的自旋锁类似
u64_stats_update_begin(&stats->syncp); // 开始上锁
stats->rx_packets++; // 统计数据包的个数
stats->rx_bytes += skb->len; // 记录数据包中数据的大小
u64_stats_update_end(&stats->syncp);// 结束锁状态
if (!(vport->ops->flags & VPORT_F_TUN_ID)) // 这是种状态处理
OVS_CB(skb)->tun_key = NULL;
// 其实呢这个函数中下面这行代码才是关键,如果不是研究openVswitch而是为了工作,个人觉得没必要(估计也不可能)
// 去弄清楚每条代码的作用。只要知道大概是什么意思,关键代码有什么作用,如果要添加自己的代码时,该往哪个地方添加就可以了。
// 下面这行代码是处理数据包的函数调用,是整个openVswitch的核心部分,传入的参数和接受数据包函数是一样的。
ovs_dp_process_received_packet(vport, skb);
}
~~~
俗话说有接必有还,有进必有出嘛。上面的是数据包进入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中。
~~~
// 这是数据包发送函数。参数vport:指定由哪个端口发送出去;参数skb:指定把哪个数据包发送出去
int ovs_vport_send(struct vport *vport, struct sk_buff *skb)
{
// 这是我自己加的代码,为了过滤掉ARP数据包。这里额外的插一句,不管在什么源代码中添加自己的代码时
// 都要在代码开头处做上自己的标识,因为这样不仅便于自己修改和调试、维护,而且也让其他人便于理解
/*===========yuzhihui:==============*/
if (0x806 == ntohs(skb->protocol)) {
arp_proc_send(vport,skb);// 自定义了一个函数处理了ARP数据包
}
// 在前篇数据结构中讲了ops是vport结构中的一些操作函数的函数指针集合结构体
// 所以vport->ops->send()是函数指针来调用函数,把数据包发送出去
int sent = vport->ops->send(vport, skb);
if (likely(sent)) { // 定义了一个判断宏likely(),如果发送成功执行下面
struct pcpu_tstats *stats; // 下面的这些代码是不是觉得非常眼熟,没错就是接受函数中的那些代码
stats = this_cpu_ptr(vport->percpu_stats);
u64_stats_update_begin(&stats->syncp);
stats->tx_packets++;
stats->tx_bytes += sent;
u64_stats_update_end(&stats->syncp);
}
return sent; // 返回的sent是已经发送成功的数据长度
}
~~~
这两个函数就是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](http://blog.csdn.net/yuzhihui_no1/article/details/39298321)
如有不正确之处,望大家指正,谢谢!!!
- 前言
- OVS datapath模块分析:packet处理流程
- openVswitch(OVS)源代码分析之简介
- openVswitch(OVS)源代码分析之数据结构
- openVswitch(OVS)源代码分析之工作流程(收发数据包)
- openVswitch(OVS)源代码分析之工作流程(数据包处理)
- openVswitch(OVS)源代码分析之工作流程(key值得提取)
- openVswitch(OVS)源代码分析之工作流程(flow流表查询)
- openVswitch(OVS)源代码的分析技巧(哈希桶结构体为例)
- openVswitch(OVS)源代码分析之工作流程(哈希桶结构体的解释)
- openVswitch(OVS)源代码之linux RCU锁机制分析
- openVswitch(OVS)源代码分析 upcall调用(之linux中的NetLink通信机制)
- openVswitch(OVS)源代码分析 upcall调用(一)