OVS(openvswitch)是开源的虚拟交换机。也是当前市场上云环境中部署份额最大的交换机。支持 openflow协议,ovsdb协议管理。
一个OVS实例包括,ovsdb-server、ovs-vswitchd、datapath快转模块(linux内核中实现,可选的。dpdk模式是在用户态实现快转,并不需要内核态的datapath模块)。
上图从整体架构说明了ovs的工作方式。ovs包括ovsdb配置管理方式和openflow流表转发控制方式。
ovsdb-server和ovs-vswitchd之间是通过socket交互信息。
ovs-vswitchd通过netlink和内核态快转模块通信。
比如通过ovs-vsctl命令增加ovs交换机接口,ovs-vsctl会通过ovsdb-server向ovsdb更新数据,ovs-vswitchd监测到ovsdb变化时,会更新交换机配置,比如添加接口。
dpdk方式的ovs除了不使用内核模块外,架构和图中相同。
ovsdb_idl_create建立一个ovsdb的连接session,形如:idl =ovsdb_idl_create(remote, &ovsrec_idl_class, true, true)。
remote类似:unix:/var/run/openvswitch/db.sock。
后续使用该idl(struct ovsdb_idl)和ovsdb通信,更新数据。
使用jsonrpc_session_recv函数接收数据,形如:msg = jsonrpc_session_recv(idl->session)。
接收消息的结构是:
struct jsonrpc_msg {
enum jsonrpc_msg_type type;
char *method; /* Request or notification only. */
struct json *params; /* Request or notification only. */
struct json *result; /* Successful reply only. */
struct json *error; /* Error reply only. */
struct json *id; /* Request or reply only. */
};
其中type是JSON-RPC 1.0定义的消息类型,包括request、notification、reply、error:
/* Messages. */
enum jsonrpc_msg_type {
JSONRPC_REQUEST, /* Request. */
JSONRPC_NOTIFY, /* Notification.*/
JSONRPC_REPLY, /* Successfulreply. */
JSONRPC_ERROR /* Error reply. */
};
params、result、error、id是不同类型的消息对应的消息数据。
当解析消息后,监测到需要更新本地数据时,调用ovsdb_idl_parse_update函数,解析消息并更新本地数据。/* A JSON value. */
struct json {
enum json_type type;
union {
struct shash *object; /* Contains "struct json *"s. */
struct json_array array;
long long int integer;
double real;
char *string;
} u;
};
type字段:说明了该json数据是联合体中的哪一种类型。
/* Type of a JSON value. */
enum json_type {
JSON_NULL, /* null */
JSON_FALSE, /* false */
JSON_TRUE, /* true */
JSON_OBJECT, /* {"a": b, "c": d, ...}*/
JSON_ARRAY, /* [1, 2, 3, ...] */
JSON_INTEGER, /* 123. */
JSON_REAL, /* 123.456. */
JSON_STRING, /* "..." */
JSON_N_TYPES
};
联合体u:表示数据可以解析的类型。
例如,当type是JSON_OBJECT类型时,且是update2更新操作,那么object字段保存着多个数据表,每张表数据中又携带着待更新的多个row数据,和每row对应的操作(modify、insert、delete、initial)。然后遍历每个表的每行数据,并执行对应的数据操作(modify、insert、delete、initial)对本地数据更新。
注:本地数据和远端的OVSDB并不相同,本地数据是vswitchd从数据库取出数据后临时放到本地结构中的。
当监听到ovsdb-server发来的rpc消息时,如果数据库发送改变就改变对应的change_seqno。后续vswitchd根据change_seqno的值是否发生了变化,决定是否重新配置ovs交换机。
在使用dpdk 类型的datapath加速之前,需要设置dpdk-init=true启动参数。
设置方法:
ovs-vsctl --no-wait set Open_vSwitch .other_config:dpdk-init=true
设置dpdk的相关参数,都通过other_config选项完成。
主要的参数有:
指定ovs是否初始化和支持dpdk端口。
指明dpdk使用的逻辑核。同dpdk的-c参数。
指明不同numa节点提前申请的大页内存。同dpdk的--socket-mem参数。
大页文件系统mount的目录。同dpdk的--huge-dir参数。
设置vhost-user 套接字的路径。
其他的dpdk配置参数。
主要包括:
1) dpdk eal初始化。
2) 启动dpdk接口状态监控线程(使用dpdk的库函数),如果状态发送变化,则更新netdev设备的变化标记。
3) 注册dpdk类型的netdev class。其中包括dpdk设备类型,ring类型、vhost、vhost client类型。
openflow交换机实现类,用来实现一个openflow交换机。主要包括创建、构造、操作openflowflow等相关方法。
datapath接口类,用来和datapath交互。主要包括datapath的open、run、端口操作、端口数据监听等相关方法。datapath是数据面的一种抽象。
网络设备抽象类,用来和网络设备交互。主要包括网卡的设置、网卡结构的抽象、数据包发送接收等相关方法。
openflow交换机实现类,用来实现一个openflow交换机。主要包括创建、构造、操作openflowflow等相关方法。
datapath接口类,用来和datapath交互。主要包括datapath的open、run、端口操作、端口数据监听等相关方法。datapath是数据面的一种抽象。
网络设备抽象类,用来和网络设备交互。主要包括网卡的设置、网卡结构的抽象、数据包发送接收等相关方法。
bridge网桥通过ofproto class构造一个openflow交换机。再通过dpif class打开(如果没有对应类型的datapath,就创建一个)对应类型的datapath通路。使用netdev class构造一个抽象网络设备,上层抽象为端口,然后对网络设备收发包等操作。
需要说明的是,datapath是按类型分类的,现在ovs有两种类型的datapath:system(对应linux内核数据通路)、netdev(dpdk用户态数据通路)。所以使用同一种datapath类型的ovs网桥共享同一个datapath对象。如下图所示。
该部分说明的内容是关于dpdk类型的datapath。
流程解释如下:
1) bridge层
1.1 struct bridge对应每个ovs网桥最上层的结构。它通过成员指针变量ofproto,联系到struct ofproto交换机结构内容。
2) ofproto层
2.1 由于联系到的struct ofproto内容是struct ofproto_dpif结构的一个up成员变量。所以通过struct ofproto地址可以cast到struct ofproto_dpif结构内容,通过该内容和dpif层交互。
2.2 通过struct ofproto_dpif的成员指针变量dpif_backer,联系到struct dpif_backer结构内容。该结构是dpif操作的入口点。
3) dpif层
3.1 通过struct dpif_backer的成员指针变量dpif,联系到structdpif结构内容。
3.2 由于struct dpif结构内容是struct dpif_netdev结构的dpif成员变量,所以通过structdpif地址可以cast到struct dpif_netdev结构内容。
3.3 struct dpif_netdev结构内容中有指针成员变量dp,通过dp可以联系到struct dp_netdev结构内容。该内容是datapath的抽象结构内容。
4) datapath层
4.1 struct dp_netdev的成员指针变量ports是一个表结构,它联系着多个port端口内容。端口的结构是struct dp_netdev_port。struct dp_netdev另外一个成员指针变量netdev,联系着dp层的struct netdev结构内容,该结构内容是网卡的逻辑抽象。
4.2 struct dp_netdev_port的指针成员变量rxqs也是一个表结构,它联系着多个队列内容。队列的结构是struct dp_netdev_rxq.它的成员变量core_id表示该队列所在的core。
4.3 通过struct dp_netdev_rxq的成员指针变量rxq,联系到dp层的struct netdev_rxq结构内容。structdp_netdev_rxq的成员变量queue_id表示该队列id。
5) netdev层
5.1 由于struct netdev结构内容是struct netdev_dpdk结构的一个up成员变量。所以通过struct netdev地址可以cast到struct netdev_dpdk结构内容。
5.2 通过struct detdev_dpdk结构内容的成员指针变量netdev_class和dpdk类型网卡交互。
5.3 由于struct netdev_rxq结构内容是struct netdev_rxq_dpdk结构内容的一个up成员变量。所以通过struct netdev_rxq地址可以cast到struct netdev_rxq_dpdk结构内容。该内容是dpdk类型的netdev_rxq,它的成员变量port_id是dpdk网络设备的port。
简要的概括下vswitchd启动的内容。
1) 和ovsdb-server通信初始化,建立
2) dpdk初始化
3) ofproto(OpenFlow交换机)初始化
4) netdev初始化
5) 网桥配置
更新网桥(添加、删除)
更新端口
创建ofproto(OpenFlow交换机),创建或打开dpif_backer
添加端口,添加到pmd中
配置网桥、端口属性
datapath run
dp_netdev的pmd更新
dpif_run(运行dpif-netdev的datapath,配置netdev等,接收发送报文)
ofproto run,配置ofproto需要的参数和功能(netflow、sflow、ipfix、mac学习)
OpenFlow控制器连接相关run
是一个OpenFlow交换机的实现类结构,提供的类功能很多,主要分为:
1. 工厂函数功能。如初始化、枚举支持的datapath类型。
2. datapath类型处理。
3. OpenFlow交换机功能。如构造、运行等。
4. OpenFlow流表功能。
5. OpenFlow配置。
6. OpenFlow计量。
7. OpenFlow 1.1 group功能。
8. 获取datapath信息功能。
9. 连接表功能。
datapath接口实现类,每种datapath都有对应的接口实现实例。dpif有两种实现类:dpif_netlink_class、dpif_netdev_class。即system、netdev。比如,dpdk的netdevdatapath类型的实现实例dpif_netdev_class。
网络设备实现类。包括抽象的设备结构和收发包功能。
dp向dpif返回的端口信息。
datapath类型共享实现实例。
datapath接口。
netdev类型的datapath的接口。
基于网络设备接口的datapath。
基于netdev类型的datapath的端口。
挂载在dp_netdev的ports成员中。
抽象的网络设备。
dpdk类型的netdev结构,继承自netdev结构。
用来表示core和队列的对应关系。
网络设备的收包队列结构,以队列区分。
dpdk的收包队列结构,继承自netdev_rxq.
端口号和netdev_dpdk中的端口号相同。
使用dpdk的接口函数rte_zmalloc申请,受dpdk的内存管理控制。
说明:本来附录是有具体的源代码的,并加了点注释,但弄上去的话,就太多了,最后就只列了下结构的名字和简要的说明。。。