我是靠谱客的博主 震动奇异果,这篇文章主要介绍OVS vswitchd启动(三十八)bridge 重配置结语,现在分享给大家,希望可以做个参考。

bridge 重配置

bridge 平滑

vswitchd启动时, bridge模块需要经过reconfigure使实际生效的配置与数据库中保持一致

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static void bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) { /* Destroy "struct bridge"s, "struct port"s, and "struct iface"s according * to 'ovs_cfg', with only very minimal configuration otherwise. * * This is mostly an update to bridge data structures. Nothing is pushed * down to ofproto or lower layers. */ add_del_bridges(ovs_cfg); HMAP_FOR_EACH(br, node, &all_bridges) { bridge_collect_wanted_ports(br, &br->wanted_ports); bridge_del_ports(br, &br->wanted_ports); } ..... }

首先调用add_del_bridges根据数据库中的记录ovs_cfg增加删除bridge, 增加是增加数据库中有而当前进程中没有的bridge, 删除是指删除数据库中没有,而进程中已有的bridge. 之后遍历每个bridge再调用bridge_del_ports, 对port进行增加和删除. 实际上,对于vswitchd启动时的reconfigure, 由于进程中原本不存在任何bridge和port, 因此此时只会按照ovs_cfg进行创建操作.

删除多余的 ofproto

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) { ...... /* Start pushing configuration changes down to the ofproto layer: * * - Delete ofprotos that are no longer configured. * * - Delete ports that are no longer configured. * * - Reconfigure existing ports to their desired configurations, or * delete them if not possible. */ bridge_delete_ofprotos(); HMAP_FOR_EACH (br, node, &all_bridges) { if (br->ofproto) { bridge_delete_or_reconfigure_ports(br); } } }

从注释中就可以看出,这一步进行的是ofproto的平滑.在bridge_delete_ofprotos中,会遍历所有ofproto,如果ofproto没有对应的bridge或者他们的type不符, 就要调用ofproto_delete将它们删除.

当完成ofproto的平滑之后, 还要删除ofproto上记录的ofport

创建缺少的 ofproto

前面将多余的ofproto删除了, 那么对于新创建的bridge, 自然也需要创建对应的ofproto

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
static void bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) { ...... /* Finish pushing configuration changes to the ofproto layer: * * - Create ofprotos that are missing. * * - Add ports that are missing. */ HMAP_FOR_EACH_SAFE (br, next, node, &all_bridges) { if (!br->ofproto) { int error; error = ofproto_create(br->name, br->type, &br->ofproto); if (error) { VLOG_ERR("failed to create bridge %s: %s", br->name, ovs_strerror(error)); shash_destroy(&br->wanted_ports); bridge_destroy(br, true); } else { /* Trigger storing datapath version. */ seq_change(connectivity_seq_get()); } } } }

对于缺失的ofproto, 会调用ofproto_create创建. 注意传入的参数是datapath_name和datapath_type

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int ofproto_create(const char *datapath_name, const char *datapath_type, struct ofproto **ofprotop) { const struct ofproto_class* class; struct ofproto* ofproto; datapath_type = ofproto_nomalize_type(datapath_type); class = ofproto_class_find__(datapath_type); ofproto = class->alloc(); /* Initialize. */ ...... error = ofproto->ofproto_class->construct(ofproto) ...... init_ports(ofproto); *ofprotop = ofproto; return 0; }

ofproto_create首先找到datapath_type对应的class, 显然会找到ofproto_dpif_class(当前ovs只有这一种),然后调用ofproto_dpif_class->alloc, 看其实现可知, 其实创建的数据结构不仅是ofproto,而是ofproto_dpif ,可以将ofproto_dpif 看作ofproto的派生类. 但alloc接口返回的还是标准的ofproto. ovs代码中很多时候都使用了这种技巧. 申请大结构,返回小结构. 上层调用使用标准的小结构作为参数, 在内部再还原成大结构. 比如这里调用construct接口,实际调用的是ofproto_dpif_class->construct()

复制代码
1
2
3
4
5
6
7
8
static int construct(struct ofproto *ofproto_) { struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_); error = open_dpif_backer(ofproto->up.type, &ofproto->backer); ..... }

这里, 会调用open_dpif_backer打开一个backer存储在&ofproto->backer.注意参数是type, 也就是说明, 每一种type对应一个backer, 即无论这种type的ofproto有多少个,始终只有一个backer.
在这里插入图片描述
上图为backer相关的数据结构。有dpif_backer、udpif、dpif,既然backer是一种type一个,那么udpif和dpif也是一种type一个,注意dpif只是基类,实际使用的结构是dpif_netdev和dpif_netlink,分别对应当前ovs支持的netdev和system两种type, open_dpif_backer在本文就不展开了,感兴趣的读者可以自行查看。

回到bridge_reconfigure, 可以看到.它还会对每个bridge进行许许多多配置, 这部分太多了, 同样也不再展开了

复制代码
1
2
3
4
bridge_configure_mirrors(br); bridge_configure_forward_bpdu(br); .....

最后bridge_reconfigure将调用bridge_run__, 这个在之前也提到过,只是那时由于vswitchd刚启动,不会有实际作用,但现在不一样了。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static void bridge_run__(void) { struct bridge *br; struct sset types; const char *type /* Let each datapath type do the work that it needs to do. */ sset_init(&types); ofproto_enumerate_types(&types); SSET_FOR_EACH (type, &types) { ofproto_type_run(type); } sset_destroy(&types); /* Let each bridge do the work that it needs to do. */ HMAP_FOR_EACH (br, node, &all_bridges) { ofproto_run(br->ofproto); } }

可以看出,关键就是对每种支持的type调用 ofproto_type_run, 对每个bridge调用ofproto_run, 一个一个来看。

ofproto_run最终调用ofproto_dpif_class->type_run()

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static int type_run(const char *type) { struct dpif_backer *backer; backer = shash_find_data(&all_dpif_backers, type); if (dpif_run(backer->dpif)) { backer->need_revalidate = REV_RECONFIGURE; } backer->recv_set_enable = true; dpif_recv_set(backer->dpif, backer->recv_set_enable); udpif_set_threads(backer->udpif, n_handlers, n_revalidators); .... }

还记得在flow子系统中说的当内核datapath收到一个报文时,会查询流表,如果没有对应表项,则会将报文上送到用户态vswitchd进程,这里type_run最重要的作用就是启动n_handlers个接收线程,接收来自内核datapath的消息。

而另一个ofproto_run, 就是运行在这个bridge上的其他协议,具体内容就等到用到时再看吧。

结语

本文和(上)篇描述了ovs系统中vswitchd进程的启动流程,其中忽略了许多旁枝末节,但总的枝干是保留的。

原文链接:https://blog.csdn.net/chenmo187J3X1/article/details/83304845

最后

以上就是震动奇异果最近收集整理的关于OVS vswitchd启动(三十八)bridge 重配置结语的全部内容,更多相关OVS内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(57)

评论列表共有 0 条评论

立即
投稿
返回
顶部