一、ovs-vswitchd 虚拟交换机功能
在 ovs-vswitchd 守护进程 介绍的 vswitchd 代码实现中,可以看到一些 bridge 相关的函数,它们实现了 Open vSwitch 虚拟交换机的主要功能。相关内容在 ovs-main/vswitchd/bridge.h 头文件和 ovs-main/vswitchd/bridge.c 文件中,主要包括以下四个函数(对应 ovs-vswitchd 进程的主循环处 bridge 相关的内容):(此处为了节约空间,对代码做了省略和细微调整)
void bridge_init(const char *remote);
void bridge_exit(bool delete_datapath);
void bridge_run(void);
void bridge_wait(void);
(1)交换机初始化模块 bridge_init()
void bridge_init(const char *remote) {
/* Create connection to database. */
idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true, true);
idl_seqno = ovsdb_idl_get_seqno(idl);
ovsdb_idl_set_lock(idl, "ovs_vswitchd");
ovsdb_idl_verify_write_only(idl);
......
/* Register unixctl commands. */
unixctl_command_register("qos/show-types", "interface", 1, 1,
qos_unixctl_show_types, NULL);
unixctl_command_register("qos/show", "interface", 1, 1,
qos_unixctl_show, NULL);
unixctl_command_register("bridge/dump-flows", "[--offload-stats] bridge",
1, 2, bridge_unixctl_dump_flows, NULL);
unixctl_command_register("bridge/reconnect", "[bridge]", 0, 1,
bridge_unixctl_reconnect, NULL);
lacp_init();
bond_init();
cfm_init();
bfd_init();
ovs_numa_init();
stp_init();
lldp_init();
rstp_init();
odp_execute_init();
ifaces_changed = seq_create();
last_ifaces_changed = seq_read(ifaces_changed);
ifnotifier = if_notifier_create(if_change_cb, NULL);
if_notifier_manual_set_cb(if_change_cb);
}
在 bridge_init 中最主要的动作是建立与 ovsdb 数据库模块的连接,并从中读取交换机的配置信息。此外还注册了相关的 unixctl 命令用于控制,并初始化了许多模块和子系统,如链路聚合控制协议 LACP、网卡绑定 bond、连续故障监测 CFM、双向转发检测 BFD、非一致内存访问 NUMA、生成树协议 STP、链路层发现协议 LLDP、快速生成树协议 RSTP、OpenFlow 数据平面 ODP 等内容。最后,创建并初始化接口变更监控。
(2)交换机退出模块 bridge_exit()
void bridge_exit(bool delete_datapath) {
if_notifier_manual_set_cb(NULL);
if_notifier_destroy(ifnotifier);
seq_destroy(ifaces_changed);
struct datapath *dp;
HMAP_FOR_EACH_SAFE (dp, node, &all_datapaths) {
datapath_destroy(dp);
}
struct bridge *br;
HMAP_FOR_EACH_SAFE (br, node, &all_bridges) {
bridge_destroy(br, delete_datapath);
}
ovsdb_idl_destroy(idl);
}
bridge_exit 用于在程序中实现退出或关闭网桥的功能,即在程序退出时安全地清理和销毁所有与网桥相关的资源,包括接口通知程序、数据路径和网桥本身。其中 bridge_exit 传入的参数 delete_datapath 用于决定在释放相关资源时是否还需要删除数据路径。
(3)交换机运行模块 bridge_run()
void bridge_run(void) {
static struct ovsrec_open_vswitch null_cfg;
const struct ovsrec_open_vswitch *cfg;
ovsrec_open_vswitch_init(&null_cfg);
ovsdb_idl_run(idl);
if_notifier_run();
......
cfg = ovsrec_open_vswitch_first(idl);
......
/* Initialize the ofproto library.
* This only needs to run once, but it must be done after the configuration is set.
* If the initialization has already occurred, bridge_init_ofproto() returns immediately. */
bridge_init_ofproto(cfg);
......
bridge_run__();
......
run_stats_update();
run_status_update();
run_system_stats();
}
这个模块负责 Open vSwitch 交换机核心逻辑的运行。首先打开 Open vSwitch 的配置数据库 ovsdb 并获取交换机相关的配置信息(比如 bridge、port 和 iface 等信息),然后进行 ofproto 的初始化。在 Bridge 和 ofproto 的区别 中提到过,在 Open vSwitch 中 bridge 和 ofproto 是一一对应的关系,用户每创建一个 bridge 系统都会相应地创建一个 ofproto 用来负责具体的功能实现,这个动作就是在这里实现的。接下来调用 bridge_run__() 函数执行 Open vSwitch 交换机的主要逻辑,如端口管理、MAC 学习、数据包转发等。最后更新相关信息,即交换机统计信息、交换机状态和系统统计信息。
(4)交换机等待模块 bridge_wait()
void bridge_wait(void) {
struct sset types;
const char *type;
ovsdb_idl_wait(idl);
......
if_notifier_wait();
sset_init(&types);
ofproto_enumerate_types(&types);
SSET_FOR_EACH (type, &types) {
ofproto_type_wait(type);
}
sset_destroy(&types);
......
system_stats_wait();
}
bridge_wait() 函数主要负责等待 Open vSwitch 交换机相关的各种事件和操作,包括 OVSDB 事务、接口通知、ofproto 执行、统计信息更新等内容。换句话说 bridge_wait() 函数是一种同步机制的实现,通过等待确保 Open vSwitch 交换机的各个组件能够正常协调和工作。
结语:
由于本人水平有限,以上内容如有不足之处欢迎大家指正(评论区/私信均可)。
参考资料:
Open vSwitch 源码阅读笔记(2)ovs-vswitchd 守护进程-CSDN博客