Open vSwitch源码阅读笔记(上)

作者简介:刘成天,就职于赛特斯信息科技股份有限公司,高级工程师,目前工作地点南京,主要从事vCPE和路由器相关的研发工作

引言

本文主要对OpenvSwitch(基于2.3.90版本)重点模块的源码实现流程做了简要的阅读记录,适合阅读OpenvSwitch源码的初级读者参考使用。在阅读源码时参照了网上很多博客尤其SDNLAB的网站文章,再次统一致谢,并将知识分享传递下去。

1. OVS网络架构

Openvswitch是一个虚拟交换机,支持Open Flow协议(也有一些硬件交换机支持Open Flow),他们被远端的controller通过Open Flow协议统一管理着,从而实现对接入的虚拟机(或设备)进行组网和互通,整体组网结构如下图:

2. OVS内部架构

  • ovs-vswitchd 主要模块,实现vswitch的守候进程daemon;
  • ovsdb-server 轻量级数据库服务器,用于ovs的配置信息;
  • ovs-vsctl 通过和ovsdb-server通信,查询和更新vswitch的配置;
  • ovs-dpctl 用来配置vswitch内核模块的一个工具;
  • ovs-appctl 发送命令消息到ovs进程;
  • ovs-ofctl 查询和控制OpenFlow虚拟交换机的流表;
  • datapath 内核模块,根据流表匹配结果做相应处理;

3. OVS代码架构


vswitchd是ovs主要的用户态程序,它从ovsdb-server读取配置并发送到ofproto层,也从ofproto读取特定的状态和统计信息并发送到数据库;

ofproto是openflow的接口层,负责和Openflow controller通信并通过ofproto_class与ofproto provider底层交互;

ofproto-dpif是ofproto接口类的具体实现;

netdev是ovs系统的网络设备抽象(比如linux的net_device或交换机的port),netdev_class定义了netdev-provider的具体实现需要的接口,具体的平台实现需要支持这些统一的接口,从而完成netdev设备的创建、销毁、打开、关闭等一系列操作;

3.1 datapath

由于openvswitch用户态代码相对复杂,首先从内核模块入手分析。
datapath为 ovs内核模块,负责执行数据处理,也就是把从接收端口收到的数据包在流表中进行匹配,并执行匹配到的动作。一个datapath可以对应多个vport,一个vport类似物理交换机的端口概念。一个datapth关联一个flow table,一个flow table包含多个条目,每个条目包括两个内容:一个match/key和一个action。

 

3.1.1 数据流向

 


一般的数据包在 Linux网络协议中的流向为上图中的蓝色箭头流向:网卡eth0收到数据包后判断报文走向,如果是本地报文把数据传送到用户态,如果是转发报文根据选路(二层交换或三层路由)把报文送到另一个网卡如eth1。当有 OVS时,数据流向如红色所示:从网卡 eth0收到报文后进入ovs的端口,根据 key值进行流表匹配,如果匹配成功执行流表对应的 action;如果失败通过upcall送入用户态处理。

3.1.2 模块初始化

内核模块采用module_init(dp_init)进行datapath的初始化,代码如下:

其中dp的genl_family注册了如下四个类型:

3.1.3 收包处理

通过vport注册的回调函数netdev_frame_hook()->netdev_frame_hook()-> netdev_port_receive()->ovs_vport_receive()处理接收报文,ovs_flow_key_extract()函数生成flow的key内容用以接下来进行流表匹配,最后调用ovs_dp_process_packet()函数进入真正的ovs数据包处理,代码流程如下:

 

 

3.1.4 流表哈希桶

流表采用hash的方式排列存放,流表的hash头结点存储数据结构如下:

该hash桶的初始化函数alloc_buckets (),生成的数据格式可参考如下:

3.1.5流表创建

用户态通过netlink进行datapath流表更新的入口函数都定义在dp_flow_genl_ops中,流表创建的入口函数是ovs_flow_cmd_new函数,代码分析如下:


根据上述流程给出流表的主要数据结构如下:

3.1.6 流表查询

流表查找主要是查表关键字的匹配,关键字数据结构如下,根据skb中的Ethernet帧生成key的函数为ovs_flow_key_extract():

流表查询的入口函数ovs_flow_tbl_lookup_stats(),flow的匹配策略是和流表中所有mask和所有key进行匹配处理,为了加速查询效率,在调用真正的流表查询函数flow_lookup()之前,对于mask的查询采用了缓存机制,实现原理是首先查询缓存的mask_cache_entry,这些cache是查询成功后形成的cache,并针对cache采用分段查询的方式,代码如下:

flow_lookup()函数的处理流程如下:

masked_flow_lookup()函数处理如下:

 

3.1.7 action处理

ovs的action类型如下,使用nla_type()函数获取nl_type的值,入口处理函数为do_execute_actions()。


OVS_ACTION_ATTR_OUTPUT:获取port号,调用do_output()发送报文到该port;
OVS_ACTION_ATTR_USERSPACE:调用output_userspace()发送到用户态;
OVS_ACTION_ATTR_HASH:调用execute_hash()获取skb的hash赋值到ovs_flow_hash
OVS_ACTION_ATTR_PUSH_VLAN:调用push_vlan()增加vlan头部

OVS_ACTION_ATTR_POP_VLAN:调用pop_vlan()移除vlan头

  • OVS_ACTION_ATTR_RECIRC:在action_fifos全局数组中添加一个deferred_action;
  • OVS_ACTION_ATTR_SET:调用execute_set_action()设置相关参数;
  • OVS_ACTION_ATTR_SAMPLE:概率性的发送报文到用户态(详见sflow章节)。

 

3.1.8 upcall处理

当没有找到匹配的流表时,内核通过netlink发送报文到用户层处理,入口函数ovs_dp_upcall(),该函数调用queue_userspace_packet()构造发往用户层的skb,通过netlink通信机制发送到用户层,其中形成的主要数据格式如下:

3.2 ovs-vswitchd

vswitchd作为守护进程和ovsdb通信以及和controller进行openflow通信,并完成和底层内核的交互。代码在vswitchd/目录下面,可以从main函数入口分析,整体处理流程如下:

分页阅读: 1 2


  • 本站原创文章仅代表作者观点,不代表SDNLAB立场。所有原创内容版权均属SDNLAB,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用,转载须注明来自 SDNLAB并附上本文链接。 本站中所有编译类文章仅用于学习和交流目的,编译工作遵照 CC 协议,如果有侵犯到您权益的地方,请及时联系我们。
  • 本文链接https://www.sdnlab.com/18668.html
分享到:
相关文章
条评论

登录后才可以评论

certusnet-sky 发表于17-03-03
10