加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

openvswitch虚拟交换机架构

(2020-04-04 12:01:50)
标签:

sdn

ovs

杂谈

分类: programming

vswitchd Overview

openvswitch虚拟交换机架构

ovs-vswitchd是OVS的关键组件,和OpenFlow控制器,OVSDB,内核模块交互。
       系统核心组件
  • 通过OpenFlow和外界通讯
  • 通过OVSDB协议和ovsdb-server通讯
  • 通过netlink和内核通讯
  • 通过netdev抽象接口和系统通讯
      实现了镜像,端口绑定,VLAN功能。
      CLI工具包括ovs-ofctl, ovs-appctl
下列示意图解释了更多细节:

因此,vswitch模块再分为下列子模块/库
  • ovs-vswitchd,vswitchd后台进程
  • ofproto,ovs桥的抽象库
  • ofproto-provider,用于控制特定类型的OpenFlow交换机的接口
  • netdev,抽象网络设备的库
  • netdev-provider,硬件和OS中的到网络设备的特定接口

2. Key Data Structures

          
openvswitch虚拟交换机架构

一个OVS网桥管理2类资源:
  • 它所控制的转发平面(datapath)
  • 连接到它的网络设备(物理的或虚拟的)(netdev)
    关键数据结构:
  •  OVS网桥实现
           ofproto, ofproto-provider.h
  • datapath管理
          dpif, dpif-provider.h
  • 网络设备管理
          netdev,netdev-provider.h

2.1 ofproto

struct ofproto抽象了OpenFlow交换机,一个ofproto实例就是一个OpenFlow交换机(网桥),
相关的数据结构(ofproto/ofproto-provider.h):
  • struct ofproto: 表示一个OpenFlow交换机(OVS网桥),所有的流/端口操作都针对ofproto
  • struct ofport 表示ofproto内的一个端口
  • struct rule: 表示ofproto内的一个OpenFlow流
  • struct ofgroup:表示ofproto内的一个OpenFlow 1.1+组
=======================================
* An OpenFlow switch.
 *
 * With few exceptions, ofproto implementations may look at these fields but
 * should not modify them. */
struct ofproto {
    struct hmap_node hmap_node;
    const struct ofproto_class *ofproto_class;
    char *type;                
    char *name;                

   
    uint64_t fallback_dpid;    
    uint64_t datapath_id;      
    bool forward_bpdu;         
    char *mfr_desc;            
    char *hw_desc;             
    char *sw_desc;             
    char *serial_desc;         
    char *dp_desc;             
    enum ofputil_frag_handling frag_handling;

   
    struct hmap ports;         
    struct shash port_by_name;
    struct simap ofp_requests; 
    uint16_t alloc_port_no;    
    uint16_t max_ports;        
    struct hmap ofport_usage;  
    uint64_t change_seq;       
    。。。。
}


struct ofport {
    struct hmap_node hmap_node;
    struct ofproto *ofproto;   
    struct netdev *netdev;
    struct ofputil_phy_port pp;
    ofp_port_t ofp_port;       
    uint64_t change_seq;
    long long int created;     
    int mtu;
    bool may_enable;           
};
===================================

2.2 ofproto-provider

openvswitch虚拟交换机架构
 ofproto-provider是ofproto 用来直接监控OpenFlow-capable交换机,结构ofproto_class,定义在ofproto/ofproto-provider.h,定义了接口来为新的硬件和软件实现一个ofproto provider

OpenvSwitch定义了内嵌的ofproto providerofproto-dpif, 这是基于库dpif以控制datapaths,一个datapath是个简单的流表,此流表只需支持精确匹配流表,即没有通配符的流表,当报文到达网络设备后,数据通路(datapath)在表中查找,如果匹配,则执行相关动作,如果失配,数据通路传递报文给ofproto-dpif,ofproto-dpif维护所有的OpenFlow流表,如果报文在这匹配了流表,ofproto-dpif执行相应的动作,并把匹配的流表项插入到dpif流表, (否则ofproto-dpif吧报文上交给ofproto并发送到OpenFlow控制器)。

dpif库继而授权它的大部分功能给一个dpif provider,上图表示了dpif providers如何适配进Open vSwitch架构

2.3 netdev

Open vSwitch库,定义在lib/netdev-provider.h,实现在lib/netdev.c,此库抽象和网络设备交互接口,即以太网接口。交换机上的每一个端口都有一个对应的netdev并支持最小的操作,比如读取netdev的MTU值,得到RX/TX的队列大小。netdev库是在netdev provider之上的一个薄层,解析如下:

2.4 netdev-provider

openvswitch虚拟交换机架构

struct netdev_class,定义在lib/netdev-provider.h,定义了实现netdev的接口,结构中包含了很多函数指针。在 netdev provider实现了以后,可以选择移植策略是在用户空间实现“userspace switch”,只要所实现的netdev provider可以收发报文,因为每个报文经过ovs-vswitchd进程,所以性能很差。
如果需要高性能,在必须选择实现一个“ofproto provider”或者“dpif provider”,这依赖于几个因素:
  •    只有 ofproto provider可以充分利用硬件,支持通配符(ACL 表或者TCAM)
  • 一个dpif provider可以利用Open vSwitch内建bonding实现,LACP, 802.1ag, 802.1Q VLANs,以及其他功能,ofproto provider必须提供它自身的实现,如果硬件支持
  • dpif provider通常容易实现,但最适合软件switching,它转换通配规则为精确匹配规则,(带有可选通配掩码),这允许软件快速hash查找,但在TCAM硬件支持通配操作TCAM使用效率低下。

netdev provider实现了到网络设备的OS和硬件相关的接口,例如到以太网设备,Open vSwitch必须能够打开交换机上的每一个端口作为netdev,因此必须为软件或者硬件交换机实现一个“netdev provider”,上图描绘了OVS中的netdev和netdev providers,netdev的详细信息如下:
所有的netdev类型包括:
  • inux netdev(lib/netdev-linux.c,Linux平台)
    • system - netdev_linux_class
    • tap - netdev_tap_class
    • internal - netdev_internal_class
  • bsd netdev (lib/netdev-bsd.c, bsd平台)
    • system - netdev_bsd_class
    • tap - netdev_tap_class
  • windows netdev(windows 平台)
    • system - netdev_windows_class
    • internal - netdev_internal_class
  • dummy netdev(lib/netdev-dummy.c)
    • dummy - dummy_class
    • dummy-internal - dummy_internal_class
    • dummy-pmd - dummy_pmd_class
  • vport netdev(lib/netdev-vport.c, vport保有到datapath的端口的引用,可以通过netdev_open()打开)
    • tunnel class:
      • geneve
      • gre
      • vxlan
      • stt
    • patch - patch_class
  • dpdk netdev
    • dpdk_class
    • dpdk_ring_class
    • dpdk_vhost_class
    • dpdk_vhost_client_class
例如,试验在DPDK之上运行OVS,在这个方案中,OVS的内核模块被DPDK的对应部分替代,这意味着DPDK的netdev必须被实现作为这个平台的netdev-provider,如果你查看源代码,可看到在DPDK初始化代码的末尾注册了它的netdev provider类。
===========================
void
netdev_dpdk_register(void)
{
    netdev_register_provider(&dpdk_class);
    netdev_register_provider(&dpdk_ring_class);
    netdev_register_provider(&dpdk_vhost_class);
    netdev_register_provider(&dpdk_vhost_client_class);
}

dpif Provider

Open vSwitch有个内建ofproto provider,称为“ofproto-dpif”,构建与lib库之上,用于操作datapath,称为"dpif",一个“datapath”就是一个简单的flow表,只需要支持精确匹配流,即没有通配符流,当报文到达网络设备,datapath在这个表查找,如果有流匹配流,执行关联的action,如果没有匹配,datapath传递报文到ofproto-dpif,这里会维护完整的OpenFlow流表,如果报文在这个流表匹配,ofproto-dpif执行动作插入新表项到dpif流表,(否则ofproto-dpif 传递报文到ofproto并发送报文给控制器)。

在计算dpif流,ofproto-dpif产生精确匹配流来描述失配报文,它基于交换机的配置和OpenFlow 流表,尽力提取可以进行通配的字段,dpif可以忽略推荐的通配符并仅仅支持精确匹配,然而,如果dpif支持通配符,则它可以使用掩码匹配多个流,基于更少的表项,并潜在的极大的减少了基于ofproto-dpif失配产生的ofproto-dpif流的数量。

“dpif”库授权它的大部分功能给“dpif provider”,下图显示了dpif providers如何适配到Open vSwitch架构
openvswitch虚拟交换机架构

struct dpif_class,定义在lib/dpif-provider.h,定义了接口来为新的硬件或软件平台实现新的dpif provider,这个结构含有很多函数指针,当前的两个实现可以作为参考例子:
  • lib/dpif-netlink.c,是Linux相关的dpif实现,和 Open vSwitch关联内核模块工作,Open vSwitch内核模块执行所有的交换工作(代码在 “datapath”目录),传递未匹配报文到用户空间,这个dpif实现是所有到内核模块的调用的封装。
  • lib/dpif-netdev.c,是个dpif的通用实现,在内部执行所有的交换功能,这实现了所有用户空间的交换实现。


===========================

3. Call Flows

 openvswitch虚拟交换机架构
vswitchd 模块的进入点在vswitchd/ovs-vswitchd.c,它的逻辑功能框图如上所示;在起始阶段,初始化网桥模块,定义在vswitchd/bridge.c,网桥模块从ovsdb获取配置参数;

之后ovs-vswitchd进入主循环,在循环中的第一件事是初始化一些库,包括DPDK,以及最重要的,ofproto库。

然后每个datapath调用ofproto_type_run()来完成开始工作,此函数再调用每个datapath类型对应的type_run实现。

随后每个bridge调用ofproto_run()开始工作,再调用每个ofproto class的run()实现.

然后ovs-vswitchd处理从ovs-appctl和ovsdb-server来的JSON-RPC消息.

netdev_run()用来处理所有的netdevs

这些工作之后,网桥,unixctl server,netdev模块进入阻塞状态,等待新的信号触发。
伪代码如下:
==========================
int main()
{
   
    bridge_init();

   
    while (!exiting) {
       
        bridge_run()
          |
          |--dpdk_init()
          |--bridge_init_ofproto() // init bridges, only once
          |--bridge_run__()
              |
              |--for(datapath types):
                     ofproto_type_run(type)
              |--for(all_bridges):
                     ofproto_run(bridge) // handle messages from OpenFlow Controller

        unixctl_server_run(unixctl);
        netdev_run();

       
        bridge_wait();
        unixctl_server_wait(unixctl);
        netdev_wait();

       
        poll_block();
    }
}

==========================

4. Procedures and Submodules


先看看bridge_init()具体内容
=================================

void
bridge_init(const char *remote)
{
   
    idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true, true);

   
    unixctl_command_register("qos/show-types", "interface", 1, 1)
    ...
    unixctl_command_register("bridge/dump-flows", "bridge", 1, 1,)

   
    lacp_init(); // register command lacp/show
    bond_init(); // register bond commands
    cfm_init();
    bfd_init();
    ovs_numa_init();
    stp_init();
    lldp_init();
    rstp_init();
    ifnotifier = if_notifier_create(if_change_cb, NULL);
}
==============================
ovs-vswitchd首先创建到ovsdb-server类型为OVSDB-IDL的连接,IDL是接口定义语言(Interface Definition Language)的缩写;OVSDB-IDL维护一个数据库在内存中的复制,它发起RPC请求到一个OVSDB数据库服务器并解析响应,转换JSON数据为客户端容易使用的数据结构,OVSDB IDL定义在ovsdb-idl.h。

unixctl_command_register()用来注册一个unixctl 命令,这样可以通过CLI控制ovs-vswitchd,每一个组模块调用此函数来注册自命令并对外输出此命令,如开始提到的,和vswitchd 交互的命令行工具是ovs-appctl,可以验证这些注册的命令。
================================

================================
在bridge_init()末尾,一些vswitchd 子模块被初始化,包括LACP, BOND, CFM, BDF, NUMA, STP, LLDP, RSTP, and inotifiers.

ovs-vswitchd的内部结构示例:

openvswitch虚拟交换机架构

4.2. ofproto library init

ofproto维护了一个注册的ofproto class数组,ofproto_classes,定义在ofproto/ofproto.c:
==========================

static const struct ofproto_class **ofproto_classes;
static size_t n_ofproto_classes;
static size_t allocated_ofproto_classes;
============================
ofproto_init()中,内嵌ofproto class类ofproto_dpif_class将被注册,这定义在ofproto/ofproto-dpif.c:
=========================
const struct ofproto_class ofproto_dpif_class = {
    init,
    ...
    port_alloc,
    port_construct,
    port_destruct,
    port_dealloc,
    port_modified,
    port_query_by_name,
    port_add,
    port_del,
    ...
    ct_flush,                  
};
===========================
ofproto_dpif_class的init()函数将注册它自己的unixctl 命令
--------------------------
static void init(const struct shash *iface_hints)
{
    struct shash_node *node;

   
    SHASH_FOR_EACH(node, iface_hints) {
        const struct iface_hint *orig_hint = node->data;
        struct iface_hint *new_hint = xmalloc(sizeof *new_hint);

        new_hint->br_name = xstrdup(orig_hint->br_name);
        new_hint->br_type = xstrdup(orig_hint->br_type);
        new_hint->ofp_port = orig_hint->ofp_port;

        shash_add(&init_ofp_ports, node->name, new_hint);
    }

    ofproto_unixctl_init();
    ofproto_dpif_trace_init();
    udpif_init();
}

-----------------------------




0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有