前段时间无意触发了一个删除dp流表的操作,然后出现流量依然正常的奇怪现象,遂对其进行了分析,走查了一下代码,本文记录一下。
现象描述
现象:ping一个虚机的fip的时候的同时,使用ovs-dpctl del-flow ufid:xxxx
删除dp里的流表,发现流量依然正常没有中断,并且通过ovs-dpctl dump-flows
却没有发现重新创建flow。
社区类似现象
问题分析
分析本问题,首先需要摸清ovs接收到普通报文后,如何进行流表处理的:
1.当ovs的datapath接收到报文后,首先会提取报文的端口信息,源目的ip/mac等信息
2.查看内核里的flow table,如果命中了就直接执行action
3.如果没有命中,则通过netlink upcall上送给用户态的ovs-vswitchd处理
4.ovs-vswitchd 查询用户态精确流表和模糊流表
5.如果模糊命中, ovs-vswitchd 会同时刷新用户态精确流表和内核态精确流表;如果精确命中,则只更新内核态流表。
6.刷新后,重新把该数据包注入给内核态 datapath 模块处理。
7.datapath 重新发起选路,查询内核流表,匹配;报文转发,结束
好了,在我们的认知里,上述流程主要针对流量的首包。
那么本问题的现象里,却是另一种情形,ovs datapath已经生成了flow,但是把它给删了,会造成什么后果呢?
进一步地,我们查看了后续dp的flow匹配统计:
在这里我们发现dp flow的统计里,报文不再hit命中,而是一直在missed,也就是一直上送vswitchd处理了。
在此,我们就基本确认了,删除dp flow后为什么流量依然正常:原因就是后续报文一直被上送给了vswitchd处理。
那接下来,我们分析为什么没有生成新的flow
这一部分的分析,需要理解upcall中如何通知datapath创建flow的处理,细节在函数handle_upcalls
:
static void |
vswitchd通知datapath创建flow:通过netlink下发DPIF_FP_CREATE
指令给datapath。
那么我们可以把问题范围缩小到if (should_install_flow(udpif, upcall))
包含的这一块代码:
是should_install_flow
判断为false了吗?
1.查看本函数的实现细节,只要是miss upcall的报文,该判断一般都是true的,暂时排除;
2.那么问题就应该是ukey_install
判断为false了,于是在该函数的内部,我们加了打印后,基本确认了问题所在。
原来在首包进行ukey_install
后,vswitchd就缓存了一份包含该flow的ukey,而ukey的索引是通过flow的ufid来唯一确认的。如果在进行ukey_install
的时候,查询ukey存在的话,就会返回false。
那么:
1.通过dpctl del-flow
是无法触发vswitchd删除该ukey,所以该ukey会在vswitchd里缓存一段时间。
2.只要vswitchd没有重启的话,flow对应的ufid也是不会变化的。
再基于以上这两个前提,我们不难分析出:当删除了dp的flow后,后续报文upcall给vswitchd,而vswitchd是能查到已有的ukey->ufid的,所以也就不会再创建新的flow。
问题总结
到这里,问题基本就确认了,将dp flow删除后,报文会一直upcall;而由于vswitchd里缓存了对应的ukey,所以upcall的报文也就不会下发新的flow了。
当然,ovs-doc里也是不建议通过dpctl操作流表:
DATAPATH FLOW TABLE DEBUGGING COMMANDS |
所以大家在操作的时候一定注意,尽量避免通过dpctl去操作流表,当然查询流表是允许的。
个人分析,欢迎指正,若转载请注明出处!