2. 使用DPDK抓包和发包
通过hello world,知道了如何启动DPDK多核程序
那么每个核如何抓某个网卡的数据报文,以及如何从某个网卡发送报文
下面分析l2fwd样例程序:
1. rte_eal_init
2. l2fwd_parse_args(argc, argv)
DPDK应用程序可以带有自己的参数通过--和eal参数区分如:
./test -cf -n4 -- -p f
3. 创建pkt mbuf pool 初始化接收缓存
l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create();
4. 计算时间周期
timer_period *= rte_get_timer_hz()
5. 获取网卡数量
nb_ports = rte_eth_dev_count()
6. 设置每个端口的发送目的端口
int last_port = 0;
int count = 0;
for (portid = 0; portid < nb_ports; portid++) {
if ((port_mask & (1 << portid)) == 0) continue;
if (count % 2 == 0) {
last_port = portid;
} else {
dst_port[portid] = last_port;
dst_port[last_port] = portid;
}
count++;
}
7. 设置每个lcore的rx接口
8. 初始化接口
A. 配置端口:
int rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_queue,
uint16_t nb_tx_queue, const struct rte_eth_conf *eth_conf);
rte_eth_dev_configure(portid, 1, 1, &port_conf);
B. 获取端口MAC地址
rte_eth_macaddr_get(uint8_t port_id, struct ether_addr *mac_addr);
rte_eth_macaddr_get(portid, &l2fwd_ports_eth_addr[portid]);
C. 初始化接收队列
int rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,
uint16_t nb_rx_desc, unsigned int socket_id,
const struct rte_eth_rxconf *rx_conf,
struct rte_mempool *mb_pool);
rte_eth_rx_queue_setup(portid, 0, nb_rxd,
rte_eth_dev_socket_id(portid), NULL, l2fwd_pktmbuf_pool);
D. 初始化发送队列
int rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,
uint16_t nb_tx_desc, unsigned int socket_id,
const struct rte_eth_txconf *tx_conf);
rte_eth_tx_queue_setup(portid, 0, nb_txd,
rte_eth_dev_socket_id(portid), NULL);
E. 初始化发送缓存
void *
rte_zmalloc_socket(const char *type,
size_t size, unsigned align, int socket);
tx_buffer[portid] = rte_zmalloc_socket("tx_buffer",
RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0,
rte_eth_dev_socket_id(portid));
rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST);
rte_eth_tx_buffer_set_err_callback(tx_buffer[portid],
rte_eth_tx_buffer_count_callback,
&port_statistics[portid].dropped);
F. 开启接口设备
rte_eth_dev_start(portid);
G. 让设备进入混杂模式
rte_eth_promiscuous_enable(portid);
9. 检查每个接口的链接状态
rte_eth_link_get_nowait(portid, &link);
10. 每个核执行l2fwd_launch_one_lcore函数,主核也进入,然后等待从核
rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASK);
11. rte_eal_mp_remote_launch() 执行 l2fwd_main_loop();
12. l2fwd_main_loop()
A. 如果此lcore有接收接口,就放这个接收接口的目的端口,发送数据到这个接口
portid = l2fwd_dst_ports[qconf->rx_port_list[i]];
buffer = tx_buffer[portid];
rte_eth_tx_buffer_flush(portid, 0, buffer);
static inline uint16_t
rte_eth_tx_buffer_flush(uint8_t port_id, uint16_t queue_id,
struct rte_eth_dev_tx_buffer *buffer)
B. 周期性显示统计信息
C. 接收数据
struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
portid = qconf->rx_port_list[i];
nb_rx = rte_eth_tx_burst(portid, 0, pkts_burst, MAX_PKT_BURST);
l2fwd_simple_forward(m, portid)
13. l2fwd_simple_forward()
l2fwd_mac_updating
rte_eth_tx_buffer(dst_port, 0, buffer, m);
14. 等待核心结束
rte_eal_wait_lcore(lcore_id)
15. 关闭接口释放内存
rte_eth_dev_stop()
rte_eth_dev_close()
rte_mbuf_free();
现在我们能够启动多核程序,以及在每个核中进行抓包,发包
之后就是对报文进行处理,也就是数据开发
这就得继续学习DPDK的<<程序开发指南>>和<
> <>