最近遇到了一个关于缓存的坑,所以需要查看代码整理一下哪些情况下会有缓存报文,啥时候不会丢,啥时候会丢,OVS版本2.7.0,DPDK16.11.1版本。
我们知道报文需要缓存一般就是不知道如何转发时,这个就涉及到常见的几个点了,最终结果就是哪都不缓存报文,全是全量报文往上给和往下发。
- datapath层如果EMC和megaflow没有匹配时,DPDK版是直接查找上一级表,直到找到匹配的流表,然后转发,不会缓存
- kernel版datapath则需要通过netlink上报,这时候0拷贝一个新的报文上报,源报文释放了,而生成的流表会带着报文一起根据netlink下发过来,最终新生成一个报文,根据流表转发。
- ofproto classifier层的话,常见的一个点是依然没有匹配的流表,需要packet in到controller的时候,报文也是全量上传给controller,所以buffer_id一直都是全f,这个就是ovs的实现。controller下发流表的时候不会带着报文,所以除了下发flow_mod,需要额外的packet_out才能保证首包下发。
- 目前已知的另一个点是dpdk版的datapath的时候,tnl封装后,需要用到ovs的arp表时,arp相关信息不存在时,则不下发流表和报文,所以也不涉及缓存的问题。
DPDK版
datapath层
pmd_thread_main-->dp_netdev_process_rxq_port-->dp_netdev_input-->dp_netdev_input__-->fast_path_processing-->handle_packet_upcall
中就是直接调用dp_netdev_upcall
去查找匹配的流表,这个时候因为大家都处在userspace层,所以就直接API调用,找到流表后安装,接着执行action即可,是一个串行的处理流程,所以不需要有报文缓存。
ofproto classifier层
handle_packet_upcall-->dp_netdev_upcall-->upcall_cb-->process_upcall-->upcall_xlate-->xlate_actions-->do_xlate_actions
列出来我们关注的点
- 首先会根据arp的回复拿到ip对应的mac地址,然后存入arp缓存中,老化时间默认15分钟
- 如果匹配到controller的流表,并且需要封装报文的时候,会查询arp缓存,查不到就不生成流表,报文也就销毁了。
- 没有匹配,则调用
execute_controller_action
生成packet_in相关信息的报文,然后通过ofproto_dpif_send_async_msg
将信息放入ofproto
main-->bridge_run-->bridge_run__-->ofproto_type_run-->dpif_run-->run-->connmgr_send_async_msg-->ofputil_encode_packet_in_private-->ofputil_encode_ofp12_packet_in
会从ofproto拿到信息然后封装为packet_in报文,然后buffer_id都是-1,报文全部上传,所以就不存在缓存报文的问题了。
main-->bridge_run-->bridge_run__-->ofproto_run-->handle_openflow-->handle_openflow__
是处理openflow消息的操作,我们关注几点
- packet_out的buffer_id如果不是-1,就会报错,意思是packet_out要么自己生成报文,然后给到ovs进行发送,比如ovn中需要发送免费arp时就是调用的packet_out,要么就是之前packet_in上传过来的报文。配合上面的意思就是老子packet_in的时候不缓存报文,你也表骗老子去找缓存,想发包就拿全量包过来。
- flow_mod不关心buffer_id,因为之前没有缓存报文,所以不涉及openflow协议中涉及的缓存报文的处理,只负责下发流表,所以需要packet_out配合。
kernel版
datapath层
netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet
首先调用ovs_flow_tbl_lookup_stats
查找流表,查找不到则需要调用ovs_dp_upcall
上报一个新生成的报文,但是0拷贝了skb的数据。
接下来是接收用户态的netlink报文后的操作。ovs_packet_cmd_execute-->ovs_execute_actions
中会重新创建一个skb,然后讲内容从netlink的数据中拷贝报文数据,所以相当于没有缓存。最后根据flow信息将报文转发。
ofproto classifier层
udpif_start_threads-->udpif_upcall_handler-->recv_upcalls-->process_upcall-->upcall_xlate-->xlate_actions-->do_xlate_actions-->execute_controller_action
参照上面。
udpif_start_threads-->udpif_upcall_handler-->recv_upcalls-->handle_upcalls-->dpif_operate-->dpif_netlink_operate-->dpif_netlink_operate__-->dpif_netlink_encode_execute-->nl_msg_put_genlmsghdr
下发netlink报文。