是基于2.3.90的版本
OVS全名字Openvswitch,是一个虚拟交换机,支持Open Flow协议,被远端的controller通过Open Flow协议统一管理着,从而实现对接入的虚拟机(或设备)镜像组网和互通,整体组网结构如下:
由于openvswitch用户态代码相对复杂,首先从内核模块入手分析。
datapath为ovs内核模块,负责执行数据处理,也就是把从接收端口收到的数据包在流表中进行匹配,并执行匹配到的动作。一个datapath可以对应多个vport,一个vport类似物理交换机的端口概念。一个datapath关联一个flow table,一个flow table包含多个条目,每个条目包括两个内容:一个match/key和一个action
一般的数据包在linux网络协议中的流向为上图中的蓝色箭头流向:网卡eth0收到数据包后判断报文走向,如果是本地报文把数据传送到用户态,如果是转发报文根据选路(二层交换或三层路由)把报文送到另一个网卡如eth1.当有OVS时,数据流向如红色所示:从网卡eth0收到报文后进入ovs的端口,根据key值进行流表匹配,如果匹配成功执行流表对应的action;如果失败通过upcall送入用户态处理。
内核模块采用 module_init(dp_init)进行 datapath 的初始化,代码如下:
其中 dp 的 genl_family 注册了如下四个类型:
通过 vport 注册的回调函数 netdev_frame_hook()->netdev_frame_hook()->
netdev_port_receive()->ovs_vport_receive()处理接收报文,ovs_flow_key_extract()
函数生成 flow 的 key 内容用以接下来进行流表匹配,最后调用 ovs_dp_process_packet()
函数进入真正的 ovs 数据包处理,代码流程如下:
流表采用 hash 的方式排列存放,流表的 hash 头结点存储数据结构如下:
该 hash 桶的初始化函数 alloc_buckets (),生成的数据格式可参考如下:
用户态通过netlink进行datapath流表更新的入口函数都定义在dp_flow_genl_ops中,流表创建的入口函数是ovs_flow_cmd_new函数,、
代码分析如下:
根据上述流程给出流表的主要数据结构如下:
流表查找主要是查表关键字的匹配,关键字数据结构如下,根据 skb 中的 Ethernet 帧
生成 key 的函数为 ovs_flow_key_extract():
流表查询的入口函数 ovs_flow_tbl_lookup_stats(),flow 的匹配策略是和流表中所有
mask 和所有 key 进行匹配处理,为了加速查询效率,在调用真正的流表查询函数
flow_lookup()之前,对于 mask 的查询采用了缓存机制,实现原理是首先查询缓存的
mask_cache_entry,这些 cache 是查询成功后形成的 cache,并针对 cache 采用分段查询
的方式,代码如下:
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_RECIRC:在 action_fifos 全局数组中添加一个 deferred_action;
13 / 30
OVS_ACTION_ATTR_SET:调用 execute_set_action()设置相关参数; OVS_ACTION_ATTR_SAMPLE:概率性的发送报文到用户态(详见 sflow 章节)。
当没有找到匹配的流表时,内核通过 netlink 发送报文到用户层处理,入口函数
ovs_dp_upcall(),该函数调用 queue_userspace_packet()构造发往用户层的 skb,通过
netlink 通信机制发送到用户层,其中形成的主要数据格式如下:
vswitchd 作为守护进程和 ovsdb 通信以及和 controller 进行 openflow 通信,并完成
和底层内核的交互。代码在 vswitchd/目录下面,可以从 main 函数入口分析,整体处理流
程如下:
ofproto 层通过 ofproto_class 类(实现是 ofproto_dpif_class)实现了 openflow 的
接口,它主要包括如下几个接口类对象:
ofproto 代表了一个 openflow switch 的具体实现,是 ofproto 层的整体结构体;
ofport 代表了一个 openflow switch 的端口,关联一个 netdev 设备;
ofrule 代表了一条 openflow 规则,rule 里面包含一组 actions;
ofgroup 代表了一个 openflow 的行为组合,openflow 1.1+以上版本支持;
其中 rule 和 group 的创建流程不在本节列出
udpif 接口层采用多个线程处理内核发往用户层的 upcall 请求,入口函数为
udpif_set_threads(),主要处理流程如下
OpenFlow 是用于管理交换机流表的协议,ovs-ofctl 则是 OVS 提供的命令行工具。
在没有配置 OpenFlow controller 的模式下,用户可以使用 ovs-ofctl 命令通过
OpenFlow 协议去连接 OVS,创建、修改或删除 OVS 中的流表项,并对 OVS 的运行状况进
行动态监控。
在 bridge_reconfigure()函数中调用 bridge_configure_remotes 进行 openflow 连接
的相关处理,主要创建两个对象:ofconn 作为客户端负责和远端 conntroller 主动建立连
接;ofservice 作为服务器提供被动式的监听服务,主要数据结构及流程如下图:
openflow 协议消息处理入口函数是 handle_openflow(),其中最重要的是 flow_mod 流
表项的处理,flow_mod 流表的报文格式主要有四部分组成:openflow 头部、flow_mod 固
定字段、match 字段和 instruction 字段。
match 分为 OFPMT_STANDARD 和 OFPMT_OXM 两种类型,可以包含多个 oxm,instruction
可以包含多个 action,也可以没有。抓包示例可参考如下:
match 字段的解析处理入口函数为 ofputil_pull_ofp11_match(),其中的核心处理函数
为 nx_pull_raw(),主要流程是解析出 flow_mod 的 match 字段,和 flow 中的 match 相关参
数做一些合法性检测,最后使用解析出的 value 更新 flow 中的 match。
目前 match 匹配域用的较多的是 OXM 即 TLV 格式,字段解析结构示意图如下:
原文链接:
采样流 sFlow(Sampled Flow)是一种基于报文采样的网络流量监控技术,主要用于
对网络流量进行统计分析。sFlow 系统包含一个嵌入在设备中的 sFlow Agent 和远端的
sFlow Collector。其中,sFlow Agent 通过 sFlow 采样获取本设备上的接口统计信息和数
据信息,将信息封装成 sFlow 报文,当 sFlow 报文缓冲区满或是在 sFlow 报文缓存时间超
时后,sFlow Agent 会将 sFlow 报文发送到指定的 sFlow Collector。sFlow Collector 对
sFlow 报文进行分析,并显示分析结果,组网图如下:
ovs-vsctl 根据用户的命令和 ovsdb-server 通信,用于查询和更新数据库配置。而
vswithcd 会在需要重新更新配置的时候和 ovsdb 交互,然后和内核 dp 模块通过 netlink
消息执行真正的操作。本节以添加网桥、端口、vxlan 端口为例分析主要实现流程,其中
ovsctl 进程的主要处理流程如下: