• OpenvSwitch中的分片与重组


    最近遇到了分片导致的一系列问题,所以在这里盘点一下OVS中都有哪些已经做了分片和重组的地方,以及还有哪些地方需要做。版本还是基于2.7.0。并且datapath的时候会分别分析OVS和OVS-DPDK两块的处理。

    up到userspace的时候

    OVS部分

    netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet-->ovs_dp_upcall主要是判定是否是带了GSO标志,如果带了,则需要将报文进行分片上报。

    OVS-DPDK部分

    pmd_thread_main-->dp_netdev_process_rxq_port-->dp_netdev_input-->dp_netdev_input__-->fast_path_processing这里不会对报文进行判定,因为目前OVS-DPDK还不支持GSO。其实个人觉得这里也没必要进行分片,因为此处报文不涉及到从kernel上报到userspace的流程。

    出端口之前

    OVS部分

    此处的分片分为两种,一种是之前因为过conntrack的时候进行了重组,那么在出口之前就要进行分片。

    netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet-->ovs_execute_actions-->do_execute_actions-->do_output这里会根据dev的mtu和报文的mru比较需要不需要分片,通常情况下报文的mru是0,不需要分片,但是因为重组函数handle_fragments重组时设置了报文的mru,所以分片时也根据此项来判定。调用ovs_fragment分片完成之后会调用ovs_vport_send-->dev_queue_xmit-->dev_hard_start_xmit-->ops->ndo_start_xmit-->bond_start_xmit进行报文发送。

    另一种的报文分片是VM中设置了TSO、GSO、UFO等features,导致报文比较大,这个时候需要根据标志判定是否需要分片。

    netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet-->ovs_execute_actions-->do_execute_actions-->do_output-->ovs_vport_send-->dev_queue_xmit-->dev_hard_start_xmit这里会根据gso进行分片,分片完成后继续调用ops->ndo_start_xmit-->bond_start_xmit进行报文发送。其实此处也会根据其他的一些特性来判定,一般比如带了TSO之类的需要网卡去分片。

    OVS-DPDK部分

    pmd_thread_main-->dp_netdev_process_rxq_port-->dp_netdev_input-->dp_netdev_input__-->packet_batch_per_flow_execute-->dp_netdev_execute_actions-->dp_execute_cb-->netdev_send-->netdev_dpdk_eth_send一般会根据网卡的特性来判定是不是分片。

    封装之前

    OVS部分

    此处的分片也分为两种,一种是之前因为过conntrack的时候进行了重组,那么在出口之前就要进行分片。

    netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet-->ovs_execute_actions-->do_execute_actions-->do_output这里会根据dev的mtu和报文的mru比较需要不需要分片,通常情况下报文的mru是0,不需要分片,但是因为重组函数handle_fragments重组时设置了报文的mru,所以分片时也根据此项来判定。调用ovs_fragment分片完成之后调用ovs_vport_send-->vxlan_xmit-->dev_queue_xmit-->dev_hard_start_xmit-->ops->ndo_start_xmit-->vxlan_xmit进行报文封装。

    另一种的报文分片是VM中设置了TSO、GSO、UFO等features,导致报文比较大,这个时候需要根据标志判定是否需要分片。

    netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet-->ovs_execute_actions-->do_execute_actions-->do_output-->ovs_vport_send-->vxlan_xmit-->dev_queue_xmit-->dev_hard_start_xmit这里会根据gso进行分片,分片完成后继续调用ops->ndo_start_xmit-->vxlan_xmit进行封装。

    OVS-DPDK部分

    pmd_thread_main-->dp_netdev_process_rxq_port-->dp_netdev_input-->dp_netdev_input__-->packet_batch_per_flow_execute-->dp_netdev_execute_actions-->dp_execute_cb

    • OVS_ACTION_ATTR_TUNNEL_PUSH的情况下会进行报文封装,调用接口push_tnl_action-->netdev_push_header-->netdev_tnl_push_udp_header进行封装,需要分片的话需要在该接口之前。
    • 调用dp_netdev_recirculate重新查表。

    重组的处理


    conntrack的时候

    OVS部分

    netdev_frame_hook-->netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet-->ovs_execute_actions-->do_execute_actions-->ovs_ct_execute中会判定报文是否分片报文,是的话调用函数handle_fragments进行重组,如果没有分片直接进行conntrack处理。

    OVS-DPDK部分

    pmd_thread_main-->dp_netdev_process_rxq_port-->dp_netdev_input-->dp_netdev_input__-->packet_batch_per_flow_execute-->dp_netdev_execute_actions-->odp_execute_actions-->conntrack_execute没有对报文分片的判定,直接进行conntrack的处理。

    解封装之后

    OVS部分

    首先是Linux Kernel接收报文,然后最终调用udp_rcv-->__udp4_lib_rcv-->udp_queue_rcv_skb-->encap_rcv会调用vxlan_rcv进行报文解封装,最终调用netdev_port_receive-->ovs_vport_receive-->ovs_dp_process_packet进行查表和转发,需要注意的是这块根本没有分片和重组。

    OVS-DPDK部分

    pmd_thread_main-->dp_netdev_process_rxq_port-->dp_netdev_input-->dp_netdev_input__-->packet_batch_per_flow_execute-->dp_netdev_execute_actions-->dp_execute_cb

    • OVS_ACTION_ATTR_TUNNEL_POP的情况下会进行报文解封装,调用接口netdev_pop_header-->netdev_vxlan_pop_header进行解封装,需要重组的话需要在该接口之后进行。
    • 调用dp_netdev_recirculate重新查表。

    匹配流表的之前

    bridge_run-->bridge_reconfigure-->ofproto_create会设置默认的分片配置。一般是normal,表示分片的源、目的端口为0。
    bridge_run-->bridge_run__-->ofproto_run-->handle_openflow-->handle_openflow__-->handle_set_config-->set_frag_handling主要是设置分片相关的配置,目前有normal、drop、reassemable、nx_match等,但是目前reassemable功能还不支持,需要我们来完成。
    rule_dpif_lookup_from_table根据不同的模式下发不同的流表。
    由以上信息可以得知,支持reassemable的话首先是不是所有的报文都进行重组,但是我们并不是所有的报文都需要重组,只有需要匹配L4的匹配项时才需要,都进行重组的话相当消耗性能,第二就是查找流表的时候还要保证分片的首包先进行流表下拉,如果不是首个分片先到,那这个报文要先缓存等待重组才行。

  • 相关阅读:
    ArrayList源码剖析
    Qt线程外使用Sleep
    malloc、calloc和realloc比较
    C++各大名库
    Qt 编译boost
    VC++ 设置控件显示文本的前景色、背景色以及字体
    std::map的操作:插入、修改、删除和遍历
    time.h文件中包含的几个函数使用时须注意事项
    赋值操作符和拷贝构造函数
    virtual析构函数的作用
  • 原文地址:https://www.cnblogs.com/dream397/p/14475282.html
Copyright © 2020-2023  润新知