九九精品九九,中字幕人妻一区二区三区,亚洲在线丝袜,亚洲欧美综合在线天堂,精品成年

探究分段場(chǎng)景下vlib_buf在收發(fā)包的處理

在使用vpp老版本copy報(bào)文的時(shí)候,經(jīng)常遇到mbuf泄露的問(wèn)題,根本原因是在vlib_buffer分段場(chǎng)景下沒(méi)有將rte_mbuf進(jìn)行串聯(lián),導(dǎo)致dpdk發(fā)包時(shí)造成了泄漏。最新的版本已經(jīng)徹底解決了此問(wèn)題。下面來(lái)分析一下:

rte_mbuf、vlib_buf 關(guān)系及內(nèi)存分布

首先,先來(lái)了解一下dpdk plugins。在plugins目錄下除dpdk_plugin.so外,其他模塊是不能直接訪問(wèn)dpdk相關(guān)函數(shù)的,vpp支持dpdk以靜態(tài)和動(dòng)態(tài)庫(kù)的方式,具體在dpdk目錄下CMakeLists.txt可以看到查詢dpdk庫(kù)。如下:

find_path(DPDK_INCLUDE_DIR PATH_SUFFIXES dpdk NAMES rte_config.h)vpp_plugin_find_library(dpdk DPDK_LIB "libdpdk.a")if (NOT DPDK_INCLUDE_DIR)  message(WARNING "-- DPDK headers not found - dpdk plugin disabled")  return()endif()if (NOT DPDK_LIB)  vpp_plugin_find_library(dpdk DPDK_SHLIB "libdpdk.so")  set(DPDK_IS_SHARED_LIB 1)  message(WARNING "-- linking dpdk plugin against DPDK shared libs")endif()

可以通過(guò)ldd命令確認(rèn)當(dāng)前使用靜態(tài)庫(kù)還是動(dòng)態(tài)庫(kù).沒(méi)有搜到libdpdk.so,就是使用的靜態(tài)庫(kù)方式。


(資料圖片僅供參考)

ldd /usr/lib/x86_64-linux-gnu/vpp_plugins/dpdk_plugin.so        linux-vdso.so.1 (0x00007ffd901cb000)        libnuma.so.1 => /usr/lib/x86_64-linux-gnu/libnuma.so.1 (0x00007fbf050a0000)        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbf04caf000)        /lib64/ld-linux-x86-64.so.2 (0x00007fbf0a3c4000)

vpp其他模塊是無(wú)法訪問(wèn)到dpdk相關(guān)的函數(shù)的,是因?yàn)関pp啟動(dòng)時(shí)以dlopen動(dòng)態(tài)加載的so庫(kù),使用需要使用需要dlsym函數(shù)負(fù)責(zé)動(dòng)態(tài)加載符號(hào)(函數(shù)),第一個(gè)參數(shù)是句柄(由dlopen時(shí)返回的),第二個(gè)參數(shù)就是給定的函數(shù)名稱。類似如下:

//鏈接并打開(kāi)動(dòng)態(tài)庫(kù)void *handle = dlopen(dlib_path, RTLD_GLOBAL | RTLD_NOW);//獲取add函數(shù)//注意:函數(shù)指針接收的add函數(shù)有幾個(gè)參數(shù)和什么返回類型要一致 CalculatorFuncPointer add_func = dlsym(handle, "add"); int add_ret = add_func(10, 20);

vpp為提供使用dlsym的接口,但是可以使用另外一種方式,就是注冊(cè)鉤子函數(shù)來(lái)解決。可以參考線程創(chuàng)建的鉤子函數(shù):

static vlib_thread_callbacks_t callbacks = {  .vlib_launch_thread_cb = &dpdk_launch_thread,  .vlib_thread_set_lcore_cb = &dpdk_thread_set_lcore,};static clib_error_t *dpdk_thread_init (vlib_main_t * vm){  vlib_thread_cb_register (vm, &callbacks);  return 0;}VLIB_INIT_FUNCTION (dpdk_thread_init);

RteMbuf內(nèi)存分布圖如下:詳細(xì)請(qǐng)閱讀以前文章:vlib ----buffer pool 內(nèi)存初始化(2)

分段場(chǎng)景下的串聯(lián)關(guān)系如下(兩段鏈表方式):

曾經(jīng)遇到過(guò)使用dpdk來(lái)申請(qǐng)報(bào)文緩存地址,在ring隊(duì)列中將rte_mbuf的內(nèi)存地址寫(xiě)異常的問(wèn)題,就是通過(guò)這種反相推理找到確認(rèn)被踩的情況。

使用dpdk-收包接口函數(shù)

vpp默認(rèn)以polling的方式來(lái)從dpdk綁定的網(wǎng)卡來(lái)收包,具體收包節(jié)點(diǎn)在src\plugins\dpdk\device\node.c文件。下面vpp從網(wǎng)卡收包節(jié)點(diǎn)的定義及節(jié)點(diǎn)函數(shù)說(shuō)明。

VLIB_NODE_FN (dpdk_input_node) (vlib_main_t * vm, vlib_node_runtime_t * node,                vlib_frame_t * f){  dpdk_main_t *dm = &dpdk_main;  dpdk_device_t *xd;  uword n_rx_packets = 0;  vnet_device_input_runtime_t *rt = (void *) node->runtime_data;  vnet_device_and_queue_t *dq;  u32 thread_index = node->thread_index;  /*輪詢此cpu上的所有設(shè)備的輸入或者中斷。會(huì)存在一個(gè)cpu綁多個(gè)接口的情況   * Poll all devices on this cpu for input/interrupts.   */  /* *INDENT-OFF* */  foreach_device_and_queue (dq, rt->devices_and_queues)    {      xd = vec_elt_at_index(dm->devices, dq->dev_instance);      n_rx_packets += dpdk_device_input (vm, dm, xd, node, thread_index,                     dq->queue_id);    }  /* *INDENT-ON* */  return n_rx_packets;}/* *dpdk-input節(jié)點(diǎn)定義* */VLIB_REGISTER_NODE (dpdk_input_node) = {  .type = VLIB_NODE_TYPE_INPUT,  .name = "dpdk-input",  .sibling_of = "device-input",  .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,  /* Will be enabled if/when hardware is detected. */  .state = VLIB_NODE_STATE_DISABLED,  .format_buffer = format_ethernet_header_with_length,  .format_trace = format_dpdk_rx_trace,  .n_errors = DPDK_N_ERROR,  .error_strings = dpdk_error_strings,};

在dpdk_device_input函數(shù)中調(diào)用dpdkpmd收包通用接口從網(wǎng)卡描述符收取報(bào)文,具體流程可以參考:DPDK 網(wǎng)卡收包流程。

下面分段報(bào)文的處理,需要通過(guò)rte_mbuf 串聯(lián)關(guān)系講vlib_buf也串聯(lián)起來(lái)。

/*通過(guò)dpdk pmd接口從網(wǎng)卡收取報(bào)文 get up to DPDK_RX_BURST_SZ buffers from PMD */  while (n_rx_packets < DPDK_RX_BURST_SZ)    {      n = rte_eth_rx_burst (xd->port_id, queue_id,                ptd->mbufs + n_rx_packets,                DPDK_RX_BURST_SZ - n_rx_packets);      n_rx_packets += n;      if (n < 32)    break;    }/*處理從網(wǎng)卡描述符收到的報(bào)文。*/static_always_inline uworddpdk_process_rx_burst (vlib_main_t * vm, dpdk_per_thread_data_t * ptd,               uword n_rx_packets, int maybe_multiseg,               u16 * or_flagsp){....while (n_left)    {      /*通過(guò)rte_mbuf的的搭配vlib-buf頭*/      b[0] = vlib_buffer_from_rte_mbuf (mb[0]);      /*前64字節(jié)賦值模板*/      vlib_buffer_copy_template (b[0], &bt);      or_flags |= dpdk_ol_flags_extract (mb, flags, 1);      flags += 1;      b[0]->current_data = mb[0]->data_off - RTE_PKTMBUF_HEADROOM;      n_bytes += b[0]->current_length = mb[0]->data_len;      /*多分段的場(chǎng)景,需要通過(guò)rte_mbuf 串聯(lián)關(guān)系講vlib_buf也串聯(lián)起來(lái)*/      if (maybe_multiseg)    n_bytes += dpdk_process_subseq_segs (vm, b[0], mb[0], &bt);      /*跟蹤記錄node執(zhí)行節(jié)點(diǎn)trace初始化*/      VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);      /* next */      mb += 1;      n_left -= 1;    }....}

使用dpdk 發(fā)包接口函數(shù)

對(duì)應(yīng)的在plugins目錄下dpdk模塊文件中src\plugins\dpdk\device\device.c定義dpdk對(duì)應(yīng)的設(shè)備類。

/*對(duì)應(yīng)的通用的dpdk tx接口函數(shù)*/VNET_DEVICE_CLASS_TX_FN (dpdk_device_class) (vlib_main_t * vm,                         vlib_node_runtime_t * node,                         vlib_frame_t * f)/* *dpdk對(duì)應(yīng)的設(shè)備類結(jié)構(gòu)體描述* */VNET_DEVICE_CLASS (dpdk_device_class) = {  .name = "dpdk",  .admin_up_down_function = dpdk_interface_admin_up_down,  .subif_add_del_function = dpdk_subif_add_del_function,  .rx_redirect_to_node = dpdk_set_interface_next_node,  .mac_addr_change_function = dpdk_set_mac_address,  .mac_addr_add_del_function = dpdk_add_del_mac_address,  .format_flow = format_dpdk_flow,  .flow_ops_function = dpdk_flow_ops_fn,  .set_rss_queues_function = dpdk_interface_set_rss_queues,};

在對(duì)應(yīng)發(fā)包函數(shù)中會(huì)對(duì)分段vlib_buf的連對(duì)應(yīng)的mbuf進(jìn)行串聯(lián),以保證在調(diào)用dpdk庫(kù)中對(duì)應(yīng)網(wǎng)卡的pmd驅(qū)動(dòng)發(fā)包接口使用。

/*判斷是否存在多段vlib_buf串聯(lián)場(chǎng)景,將對(duì)應(yīng)的mbuf也串聯(lián)起來(lái)*/      dpdk_validate_rte_mbuf (vm, b[0], 1);      /*設(shè)置網(wǎng)卡tx 卸載功能*/      dpdk_buffer_tx_offload (xd, b[0], mb[0]);

所以我們其他模塊操作分段vlib_buf時(shí),并不需要將考慮將rte_mbufd的進(jìn)行處理。比如vlib_buffer_copy中只是將vlib-buf頭進(jìn)行也串聯(lián)。

在項(xiàng)目開(kāi)發(fā)中遇到一個(gè)使用vlib_buffer_copy的問(wèn)題,就是不會(huì)賦值current_config_index字段(用于獲取當(dāng)前節(jié)點(diǎn)的next0節(jié)點(diǎn))進(jìn)行復(fù)制。會(huì)導(dǎo)致報(bào)文走到其他的幾點(diǎn)上。

總結(jié)

在使用vpp過(guò)程中,經(jīng)常遇到rte_mbuf泄露的問(wèn)題,而了解使用原理對(duì)分析問(wèn)題很有幫助。本文以報(bào)文分段場(chǎng)景的處理為背景,學(xué)習(xí)了報(bào)文從哪來(lái)(dpdk-input),到哪去(dpdk tx)的實(shí)現(xiàn)邏輯。希望本文的介紹對(duì)你有所幫助。

關(guān)鍵詞:

娛樂(lè)圖賞