1. 程式人生 > >DPDK--Skeleton 單核收發包測試案例 源碼閱讀

DPDK--Skeleton 單核收發包測試案例 源碼閱讀

port 需要 perf setting class 源碼閱讀 tdi cati count

#include <stdint.h>
#include <inttypes.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
#include <rte_cycles.h>
#include <rte_lcore.h>
#include <rte_mbuf.h>

#define RX_RING_SIZE 128        //接收環大小
#define TX_RING_SIZE 512        //發送環大小

#define NUM_MBUFS 8191
#define
MBUF_CACHE_SIZE 250 #define BURST_SIZE 32 static const struct rte_eth_conf port_conf_default = { .rxmode = { .max_rx_pkt_len = ETHER_MAX_LEN } }; /* basicfwd.c: Basic DPDK skeleton forwarding example. */ /* * Initializes a given port using global settings and with the RX buffers * coming from the mbuf_pool passed as a parameter.
*/ /* 指定網口的隊列數,本列中指定的是但隊列 在tx、rx兩個方向上,設置緩沖區 */ static inline int port_init(uint8_t port, struct rte_mempool *mbuf_pool) { struct rte_eth_conf port_conf = port_conf_default; //網口配置=默認的網口配置 const uint16_t rx_rings = 1, tx_rings = 1; //網口tx、rx隊列的個數 int
retval; //臨時變量,返回值 uint16_t q; //臨時變量,隊列號 if (port >= rte_eth_dev_count()) return -1; /* Configure the Ethernet device. */ //配置以太網口設備 //網口號、發送隊列個數、接收隊列個數、網口的配置 retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf); //設置網卡設備 if (retval != 0) return retval; /* Allocate and set up 1 RX queue per Ethernet port. */ //RX隊列初始化 for (q = 0; q < rx_rings; q++) { //遍歷指定網口的所有rx隊列 //申請並設置一個收包隊列 //指定網口,指定隊列,指定隊列RING的大小,指定SOCKET_ID號,指定隊列選項(默認NULL),指定內存池 //其中rte_eth_dev_socket_id(port)不理解,通過port號來獲取dev_socket_id?? //dev_socket_id作用未知,有待研究 retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE, rte_eth_dev_socket_id(port), NULL, mbuf_pool); if (retval < 0) return retval; } //TX隊列初始化 /* Allocate and set up 1 TX queue per Ethernet port. */ for (q = 0; q < tx_rings; q++) { //遍歷指定網口的所有tx隊列 //申請並設置一個發包隊列 //指定網口,指定隊列,指定隊列RING大小,指定SOCKET_ID號,指定選項(NULL為默認) //??TX為何沒指定內存池,此特征有待研究 retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE, //申請並設置一個發包隊列 rte_eth_dev_socket_id(port), NULL); if (retval < 0) return retval; } /* Start the Ethernet port. */ retval = rte_eth_dev_start(port); //啟動網卡 if (retval < 0) return retval; /* Display the port MAC address. */ struct ether_addr addr; rte_eth_macaddr_get(port, &addr); //獲取網卡的MAC地址,並打印 printf("Port %u MAC: %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n", (unsigned)port, addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2], addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]); /* Enable RX in promiscuous mode for the Ethernet device. */ rte_eth_promiscuous_enable(port); //設置網卡為混雜模式 return 0; } /* * The lcore main. This is the main thread that does the work, reading from * an input port and writing to an output port. */ /* //業務函數入口點 //__attribute__((noreturn))用法 //標明函數無返回值 //用來修飾lcore_main函數,標明lcore_main無返回值 */ /* //1、檢測CPU與網卡是否匹配 //2、建議使用本地CPU就近網卡???,不理解 //3、數據接收、發送的while(1) */ static __attribute__((noreturn)) void lcore_main(void) { const uint8_t nb_ports = rte_eth_dev_count(); //網口總數 uint8_t port; //臨時變量,網口號 /* * Check that the port is on the same NUMA node as the polling thread * for best performance. * 檢測CPU和網口是否匹配 * ????,不理解,姑且看作是一個檢測機制 */ for (port = 0; port < nb_ports; port++) //遍歷所有網口 if (rte_eth_dev_socket_id(port) > 0 && //檢測的IF語句 rte_eth_dev_socket_id(port) != (int)rte_socket_id()) printf("WARNING, port %u is on remote NUMA node to " "polling thread.\n\tPerformance will " "not be optimal.\n", port); printf("\nCore %u forwarding packets. [Ctrl+C to quit]\n", rte_lcore_id()); /* Run until the application is quit or killed. */ /*運行 直到 應用程序 推出 或 被kill*/ for (;;) { /* * Receive packets on a port and forward them on the paired * port. The mapping is 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2, etc. * 從Eth接收數據包 ,並發送到 ETH上。 * 發送順序為:0 的接收 到 1的 發送, * 1 的接收 到 0的 發送 * 每兩個端口為一對 */ for (port = 0; port < nb_ports; port++) { //遍歷所有網口 /* Get burst of RX packets, from first port of pair. */ struct rte_mbuf *bufs[BURST_SIZE]; //收包,接收到nb_tx個包 //端口,隊列,收包隊列,隊列大小 const uint16_t nb_rx = rte_eth_rx_burst(port, 0, bufs, BURST_SIZE); if (unlikely(nb_rx == 0)) continue; /* Send burst of TX packets, to second port of pair. */ //發包,發送nb_rx個包 //端口,隊列,發送緩沖區,發包個數 const uint16_t nb_tx = rte_eth_tx_burst(port ^ 1, 0, bufs, nb_rx); //*****註意:以上流程為:從x收到的包,發送到x^1口 //其中,0^1 = 1, 1^1 = 0 //此運算可以達到測試要求的收、發包邏輯 /* Free any unsent packets. */ //釋放不發送的數據包 //1、收到nb_rx個包,轉發了nb_tx個,剩余nb_rx-nb_tx個 //2、把剩余的包釋放掉 if (unlikely(nb_tx < nb_rx)) { uint16_t buf; for (buf = nb_tx; buf < nb_rx; buf++) rte_pktmbuf_free(bufs[buf]); //釋放包 } } } } /* * The main function, which does initialization and calls the per-lcore * functions. */ int main(int argc, char *argv[]) { struct rte_mempool *mbuf_pool; //指向內存池結構的指針變量 unsigned nb_ports; //網口個數 uint8_t portid; //網口號,臨時的標記變量 /* Initialize the Environment Abstraction Layer (EAL). */ int ret = rte_eal_init(argc, argv); //初始化 if (ret < 0) rte_exit(EXIT_FAILURE, "Error with EAL initialization\n"); argc -= ret; //??本操作莫名其妙,似乎一點用處也沒有 argv += ret; //??本操作莫名其妙,似乎一點用處也沒有 /* Check that there is an even number of ports to send/receive on. */ nb_ports = rte_eth_dev_count(); //獲取當前有效網口的個數 if (nb_ports < 2 || (nb_ports & 1)) //如果有效網口數小於2或有效網口數為奇數0,則出錯 rte_exit(EXIT_FAILURE, "Error: number of ports must be even\n"); /* Creates a new mempool in memory to hold the mbufs. */ /*創建一個新的內存池*/ //"MBUF_POOL"內存池名, NUM_MBUFS * nb_ports網口數, // MBUF_CACHE_SIZE ??, 0, RTE_MBUF_DEFAULT_BUF_SIZE ??, rte_socket_id()?? //此函數為rte_mempoll_create()的封裝 //此函數疑惑比較多,需要進一步看代碼,先放著 mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS * nb_ports, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); if (mbuf_pool == NULL) rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n"); //初始化所有的網口 /* Initialize all ports. */ for (portid = 0; portid < nb_ports; portid++) //遍歷所有網口 if (port_init(portid, mbuf_pool) != 0) //初始化指定網口,需要網口號和內存池,此函數為自定義函數,看前面定義 rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8 "\n", portid); //如果邏輯核心總數>1 ,打印警告信息,此程序用不上多個邏輯核心 //邏輯核心可以通過傳遞參數 -c 邏輯核掩碼來設置 if (rte_lcore_count() > 1) printf("\nWARNING: Too many lcores enabled. Only 1 used.\n"); /* Call lcore_main on the master core only. */ //執行主函數 lcore_main(); return 0; }

DPDK--Skeleton 單核收發包測試案例 源碼閱讀