ovs upcall处理:缓存流表生成
Posted fsz304203330
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ovs upcall处理:缓存流表生成相关的知识,希望对你有一定的参考价值。
参考资料:https://www.sdnlab.com/16171.html //upcall流程解析
https://www.sdnlab.com/15713.html //ovs内核态查表详细流程
https://zhuanlan.zhihu.com/p/66321252 //OpenVSwitch实现浅谈(二) 有对megaflow的讲解
https://www.jqhtml.com/43252.html?wpfpaction=add&postid=43252 //dpcls,这一级的包分类器其实就是[这篇论文]描述的TSS分类器介绍,这里讲了最长匹配策略,和匹配存储过程,非常重要
miss和flow作用: OVS将具有相同key的upcall归为一类,管理映射到同一个miss中。这样就完成了相似packet的分类工作,便于后期统一匹配处理,提高效率。
对应关系:一个报文生成一个upcall,一个upcall包含一个用于域匹配生成流表的flow结构;
具有相同的key值得upcall归类为一个miss,后续匹配生成缓存流表的时候统一处理;
1.相关结构体:
struct flow *flow = &flows[n_upcalls]; //存储用于由key翻译过来的flow信息;将传递上的原始key信息,翻译成后续可以和域匹配的flow结构,就是一次映射
//flow就是前面讲解到的用户层用于表示匹配域的结构体,就是提取出的报文需要用于和用户态的Openflow协议匹配的数据结构体;
//upcall->flow = flow; 在upcall_receive中以指指针形式传给了upcall flow和flow归属的upcall这样联系在一起;
struct rule { //用户态流表规则存储形式,配置的normal流表等最后都会以rule的形式存储
2. upacll用户态 接收upcall数据后处理流程
recv_upcalls //总体口
dpif_recv //从netlik获取了原始的upcall数据,并且已经解析除了key值,packet和userdata 存储在了dpupcall中
----------阶段一-------------
upcall->fitness = odp_flow_key_to_flow(dupcall->key, dupcall->key_len,flow, NULL); //将key值内容转换为flow的函数,结果存储在flow里,只通过key生成flow没有含有skb信息,通过指针传递给了upcall,返回值
//upcall->fitness 代表的是key的数据翻译成flow的匹配度
//将key中一定长度的netlink attribute解析到flow结构体中,这里并没有拿packet作为参数,
//因为现在理解的OVS_KEY_ATTR_*属性都不需要包数据。现在我们总是可以通过底层协议相关的属性来推断出其他的attributes,比如说,如果在
//OVS_KEY_ATTR_IPV4或 OVS_KEY_ATTR_IPV6中的协议值是IPPROTO_TCP,那么就会出现属性OVS_KEY_ATTR_TCP。
error = upcall_receive(upcall, udpif->backer, &dupcall->packet,dupcall->type, dupcall->userdata, flow, mru,&dupcall->ufid, PMD_ID_NULL);//这里upcall->ukey 初始化为NULL
pkt_metadata_from_flow(&dupcall->packet.md, flow); //将flow里面的一些内容赋给报文的metadata部分, metadata upcall->packet 也是通过指针形式传给upcall,所以这个函数也是完善upcall
flow_extract(&dupcall->packet, flow); //根据报文和metadata的数据,生成一条新的miniflow,然后拷贝miniflow的内容到flow,不是特别懂!!!这样新的flow比之前多了一些skb的信息。
miniflow_extract(packet, &m.mf);//该函数用于将报文内容提取出来构建miniflow结构。
miniflow_expand(&m.mf, flow);// 函数用于将miniflow还原成flow 链接:https://segmentfault.com/a/1190000020454413 这样一来一去flow里就含有了skb相关信息
//到这里upcall已经准备好了
----------阶段二-----------------
error = process_upcall(udpif, upcall,&upcall->odp_actions, &upcall->wc);
case SLOW_PATH_UPCALL: //待确认是否走这个分支,但是后续的ukey赋值只有这里进去
upcall_xlate(udpif, upcall, odp_actions, wc); //参考:https://blog.csdn.net/chen739481102/article/details/85988215
xlate_in_init(&xin, upcall->ofproto,ofproto_dpif_get_tables_version(upcall->ofproto),upcall->flow, upcall->ofp_in_port, NULL,stats.tcp_flags, upcall->packet, wc, odp_actions);
//生成xin 其中 xin->flow = *flow; *flow 是第四个参数upcall->flow 这样upcall的flow就和xin->flow指向了
xerr = xlate_actions(&xin, &upcall->xout); //这个函数里面,会在flow table里面查找rule //参考:https://www.dazhuanlan.com/2020/01/06/5e12aa7c48b37/ 详细匹配过程
ctx.rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto, ctx.xin->tables_version, flow, ctx.wc,ctx.xin->resubmit_stats, &ctx.table_id,flow->in_port.ofp_port, true, true, ctx.xin->xcache);
//这个是实际从Look up ‘flow‘ in ‘ofproto‘‘s classifier version ‘version‘查找 规则的函数。 配置不用用户态流表,同样的upall在这里应该返回不同
//normal流表和三层流表同样的upcall 下发的流表不同,需要在这里跟进打印,看是否寻找到的rule不同!!!
do_xlate_actions(ofpacts, ofpacts_len, &ctx, true, false);//在这个函数里面,根据action的不同,修改flow的内容,这里把修改后的flow内容打印出来,特别是ufid 和l3规则
//找到的流表规则rule通过 &ctx 传入
upcall->ukey = ukey_create_from_upcall(upcall, wc);//在这里对ukey进行了赋值
ukey_create__ //ukey的实际创建函数 ,在这里可以打印ufid等信息,这里是处理完后的数据了!!!!!
----------阶段三-----------------
handle_upcalls(handler->udpif, upcalls, n_upcalls);
以上是关于ovs upcall处理:缓存流表生成的主要内容,如果未能解决你的问题,请参考以下文章
Openvswitch原理与代码分析:用户态流表flow table的操作