• SDN私享汇(十一):OvS 架构介绍及开发实践


    原文:https://www.sdnlab.com/19448.html

    --------------------------------------------------------------------------------------------------
    Openvswitch是一个优秀的开源软件交换机,支持主流的交换机功能,比如二层交换、网络隔离、QoS、流量监控等,而其最大的特点就是支持openflow,openflow定义了灵活的数据包处理规范。其所支持的所有协议如STP/LACP/BOND等最后都是落脚到流表。 同时OvS 提供ofproto dpif 编程接口,支持硬件交换机(后面有介绍)。
    OvS丰富的功能和稳定性使得其被部署在各种生产环境中,加上云计算的快速发展,OvS成为了云网络里的关键组件。

    一、OvS 在SDN网络中的位置

    OvS 通过openflow流表可以实现各种网络功能,并且通过openflow protocol可以方便的实现控制+转发分离的SDN方案。

    OvS 在云环境中概图(图片来源互联网)如下

    二、OvS 各组件关系
    ovs-vswitchd:主要模块,实现内核datapath upcall 处理以及ofproto 查表,同时是dpdk datapath处理程序。
    ovsdb-server:数据库服务程序, 使用目前普遍认可的ovsdb 协议。
    ovs-vsctl:网桥、接口等的创建、删除、设置、查询等。
    ovs-dpctl:配置vswitch内核模块
    ovs-appctl:发送命令消息到ovs-vswithchd, 查看不同模块状态
    ovs-ofctl:下发流表信息。该命令可以配置其他openflow 交换机(采用openflow 协议)

    三、OvS datapath以及查找算法

    OvS 支持内核datapath以及dpdk datapath。在两种datapath模式中,内核模块和ovs-vswithd是主要的处理程序。同时两种datapath 前两级的查表实现不同,但是第三级都使用相同的ofproto 查询(这里我们只做简单介绍)。

    一直以来,流Cache是提高查表性能的有效手段,已经被广泛应用于报文查表加速。它将数据平面的转发路径分为快速路径(即流Cache)和慢速路径,利用流量局部特性,使得大部分报文命中快速路径中的表项,从而提高转发性能。OVS也采用了流Cache设计思路。

    OVS当前版本kernel datapath采用Megaflow Cache+Microflow Cache的流Cache组织形式,仍保留了Microflow Cache作为一级Cache,即报文进入后首先查这一级Cache。只不过这个Microflow Cache含义与原来的Microflow Cache不同。原来的Microflow Cache是一个实际存在的精确Hash表,但是最新版本中的Microflow Cache不是一个表,而是一个索引值,指向的是最近一次查Megaflow Cache表项。那么报文的首次查表就不需要进行线性地链式搜索,可直接对应到其中一张Megaflow的元组表。SDNLAB已经有文章对此进行了详细分析,见https://www.sdnlab.com/15713.html

    OVS + DPDK 查找算法和kernel datapath 查找有所不同,OVS DPDK查找详见 https://software.intel.com/en-us/articles/ovs-dpdk-datapath-classifier

    四、OvS 代码架构


    ovsdb-server 接收配置信息,同步到ovs-vswithd ,同时获取ovs-vswithd 状态信息。

    ovs-vswitchd ovsdb-server读取数据库信息,并将信息下发到ofproto,同时ovs-vswithd也会将ofproto中的status and statistical信息通过ovsdb-server写入到数据库中。

    ofproto通过网络和OpenFlow 控制器通信。通过"ofproto provider”和软件交换机以及硬件交换机通信。目前openvswitch只支持ofproto-dpif,但是用户可以很容易的实现其他ofproto provider

    ofproto provider 支持两种dpif,ofproto-dpif 实现自己的数据结构,但是对上层呈现为ofproto结构体,其具体实现细节对上不可见。

    netdev 对网络设备(如Ethernet)的抽象,该层基于netdev provider实现。如果linux平台的system,tap,internal,以及dpdk的dpdk,dpdkr,dpdkvhostuser,dpdkvhostuserclient等。

    创建ovs bridge流程分析:

    1.通过ovs-vsctl 创建网桥,将创建参数发送给ovsdb-server,ovsdb-server将数据写入数据库。

    2.ovs-vswitchd从ovsdb-server中读取创建网桥的信息,在ovs-vswithd层创建一个bridge结构体信息

    3.然后将brdige信息应用到ofproto层,在ofproto层通过ofproto_create创建网桥,ofproto_create通过用户指定的网桥类型查找包含该类型的ofproto provider(目前只支持一个ofproto provider)。
    查找后创建ofproto结构体(该结构体也表示一个bridge),并通过ofproto provider 构造函数创建ofproto provider的私有信息。

    4.ofproto-dpif 层,构造函数完成如下:ofproto-dpif会为相同类型的ofproto创建一个backer结构体,所有类型的ofproto的backer使用全局列表表示。ofproto-dpif通过backer关联dpif。同时backer关联upcall处理线程
    netdev没有实现upcall注册函数,所以对应的backer线程实际上不做任何处理,但依然会有该处理线程。netlink 通过backer启动的线程实现处理upcall数据包的处理。

    vswitchd是ovs中最核心的组件,openflow的相关逻辑都在vswitchd里实现,一般来说ovs分为datapath, vswitchd以及ovsdb三个部分,datapath一般是和具体是数据面平台相关的,比如白盒交换机,或者linux内核等。ovsdb用于存储vswitch本身的配置信息,比如端口,拓扑,规则等。vswitchd本身是分层的结构,最上层daemon主要用于和ovsdb通信,做配置的下发和更新等,中间层ofproto,用于和openflow控制器通信,以及通过ofproto_class暴露了ofproto provider接口,不同平台上openflow的具体实现就通过ofproto_class统一。

    Open vSwitch实现了两种dpif。lib/dpif-netlink.c 特定Linux实现的dpif,该dpif与Open vSwith实现的内核模块通信。内核模块执行所有的交换工作,将内核态不匹配的数据包发送到用户态。dpif封装调用内核接口。lib/dpif-netdev.c 是一种通用的 dpif 实现。该dpif就是Open vSwith在用户态的实现。数据包的交换不会进入内核。struct dpif_class是datapath interface实现的工厂接口类,用于和实际的datapath, e.g. openvswitch.ko, 或者userspace datapath交互。目前已有的两个dpif的实现是dpif-netlink和dpif-netdev,前者是基于内核datapath的dpif实现,后者基于用户态datapath。代码可以在lib/dpif-netlink.c以及lib/dpif-netdev.c里找到。

    五、OvS 开发实践贡献代码之前

    开发OvS 代码之前,我们需要了解如下信息
    1.邮件列表,所有的邮件列表:我们一般使用discuss作为平时问题的讨论,dev作为提patch。https://mail.openvswitch.org/mailman/listinfo

    2.编码风格,如果你为OvS用户态程序提供的patch,那么你需要遵循用户态编码风格。如果你是为内核datapath 编写的patch 你需要遵循内核编码风格。这两种是不同的风格。http://docs.openvswitch.org/en/latest/internals/contributing/coding-style/

    3.Commit Message,在提交代码时,尽量把你遇到的问题,复现方法以及你的patch如何解决该问题的等, 描写的详尽。这不仅能够让其他人更好的理解,同时缩短接收patch时间,国内外有时差。

    4.patchwork 在这里,你能够看到其他人提交的patch,同时每个patch 处于什么状态。http://patchwork.ozlabs.org/project/openvswitch/list/

    六、OvS 开发实践之二层网络功能

    OvS 支持各种二层网络功能,比如LACP,STP,RSTP,MAC 学习,MCAST等,如果这些协议出现问题,可以通过如下的开发过程,定位,开发。ovs-vswithd 结构分析,开发OvS 最重要的就是分析ovs-vswithd

    OvS 模块的初始化
    主要是模块使用的数据结构体的初始化非协议,如lacp、bond、cfm、stp、rstp都在bridge_init调用初始化

    ovs-vswithd 循环处理架构
    这里只是列出的基本重要的架构,其他部分读者可以进一步分析

    bridge_run__ 循环处理一些必要的操作,如stp、rstp、mcast处理等,同时ovs-ofctl 下发openflow,也是在这里处理。bridge_reconfigure 主要完成根据数据以及当前进程信息,创建、更新、删除必要的网桥、接口、端口以及其他协议的配置等。最终这些操作为应用到ofproto 层、ofproto dpif 层、run_stats_update、run_status_update、run_system_stats 更新openvswitch数据库状态信息netdev_run netdev_linux_run监控网卡状态并更新。

    以STP 某个功能为例,例如之前的一个bug,OvS 不会检查stp port 所处的状态。如果已经加入的port 开启的stp功能,用户使用ifconfig 禁止网卡状态,那么理论上OvS 应该停止通过该端口发送数据包括BPDU。但是OvS 并没有做这方便的检查。同时如果ifconfig up了该网卡,那么重新进入stp 状态,以及stp 各个状态的改变。

    社区最后接收了该bug的修复,patch 如下:https://github.com/openvswitch/ovs/commit/52182c5f50198d0f985b10677e47a9ac49ee709b

    添加链路状态监测函数:

    在必要的地方调用

    该补丁,在bridge_run__ stp_run中调用状态检查,并根据port 状态对stp进行响应的处理。(网卡状态的更新检查统一在netdev_run中尽心,这里我们使用最后的检查的结果做判断)同时该补丁也bridge_reconfigure bridge_configure_spanning_tree设置port时调用该函数。如果是对其他协议的bug,修复过程其实类似。

    七、OvS 开发实践之unixctl

    ovs-vswithd 支持ovs-appctl 很多命令,通过该方式,我们可以开发很多有用的功能,如查看ovs-vswithd 运行状态,数据包处理状态,内存使用情况,PMD线程情况。

    OvS unixctl的初始化
    在ovs-vswithd 初始化的时候通过unixctl_server_create函数创建unixctl 服务。命令ovs-appctl和注册的服务通信。

    OvS unixctl 命令注册
    我们可以通过unixctl_command_register 注册unixctl 提供个命令服务,如ovs-vswithd 退出函数 unixctl_command_register("exit", "", 0, 0, ovs_vswitchd_exit, &exiting)

    OvS unixctl 命令运行
    ovs-vswithd 在循环中通过调用unixctl_server_run 执行用户下发的命令。

    前段时间开发的rstp/show 命令,该命令能够查看rstp 协议在各个交换机中的状态,显示格式和思科交换机类似。在开发该功能时考虑如下 :
    1.使用重陷入锁还是使用内部函数。在实现该命令时需要调用其他函数,但是之前使用的锁不允许重入,但是如果更改rstp 使用锁的方式,需要更改大量的代码(声明,函数修饰)。
    因此最后改成添加内部帮助函数。
    2.rstp port name。之前rstp port不支持name 显示,因此为了更清晰的显示信息。我们需要在结构体中添加name 成员。

    在整个rstp port 整个声明周期(如rstp port的创建,删除,使用,修改等),我们需要处理好name。独立的patch 如下 https://github.com/openvswitch/ovs/commit/8d2f8375c7f7ee3e36877ba20f4e4cc5b47841d3

    添加必要属性 

    设置port name函数rstp_port_set_port_name__

    最后需要在rstp_add_port 初始化port name, 在rstp_port_unref 删除port name,同时在rstp 模块添加必要的内部函数,实现如下(具体很简单,大家可以review)https://github.com/openvswitch/ovs/commit/066f0ab4a07d2edc07dedcf006224df7fa00a9b1

    最后实现rstp/show命令https://github.com/openvswitch/ovs/commit/cc3a32f3b6891168cee98812e8f5e3d8a5a52c98
    最终命令效果

    Q&A

    Q:我有ovs通过vmware的wmnet桥接的,但是把桥接网卡设置成trunk后就不通了,能帮忙分析下么,ovs是安装在centos7上的,cent是安装在vmware上的
    A:这个好细节,你可以通过tcpdump 检查,每个节点是否 都有数据包,看看哪里丢包。ovs 你可以看看ovs flow表 看看哪个flow drop的该数据包。

    Q:之前提到的ovs-dpdk的datapath,请问能讲解一下ofproto是如何把流表分发给多个PMD的呢?
    A:ovs 不管哪个datapath 都是三级cache,最后一个是ofproto,dpcls miss之后才去ofproto 所以对应的dpcls 才会有,之后emc 查找去对应的dpcls 去找,一个pmd 线程可能多个dpcls

    Q:ovs流表匹配采用什么算法?对精确匹配字段,前缀匹配字段,和范围匹配字段的匹配有区别对待?
    A:ovs kernel datapath 使用Megaflow Cache + Microflow Cache,dpdk 和kernel 第一层cache 都是精准匹配,后面是通配的。如果是有区别,就是查找前后的区别。大家可以review dpdk 和kernel 的实现算法。

    Q:能介绍一下ovs -dpdk在openstack里的应用吗?
    A:ovs-dpdk 在openstack 并没有应用到实际的生产环境,如果有,也是小部分现在。不过这个是趋势。

    Q:相同优先级 match条件都一样的两条流表 怎么决定匹配到哪一条
    A:这个会对 表的优先级排序的,找到的肯定是优先级高的。

    Q:流表中的in port 和虚机端口有什么关系吗?
    A:没有

  • 相关阅读:
    XML  XmlDocument
    程序集报错
    程序打开网页
    写入文件txt
    读取文件txt
    MSM8953中Android系统添加启动脚本.rc文件
    SELinux基础知识
    嵌入式Linux设备查看USB相关信息
    Linux内核态文件读写相关函数API
    C语言中sscanf()函数相关用法
  • 原文地址:https://www.cnblogs.com/liuhongru/p/11121814.html
Copyright © 2020-2023  润新知