以下是使用DPDK发送数据包,并在已有的mbuf缓冲区前面填充以太网、IP和UDP头部的示例代码:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
#include <rte_udp.h>
#include <rte_ip.h>
#define NUM_MBUFS 8191
#define MBUF_CACHE_SIZE 250
// 定义MAC地址结构体
struct ether_addr dest_mac = {
.addr_bytes = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55} // 目标MAC地址
};
int main(int argc, char **argv) {
int ret;
// 初始化EAL环境
ret = rte_eal_init(argc, argv);
if (ret < 0)
return -1;
// 获取第一个可用的物理端口编号
uint16_t port_id;
port_id = rte_eth_find_next(0);
if (port_id == RTE_MAX_ETHPORTS)
return -1;
// 配置物理端口并启动它
struct rte_eth_conf port_conf = {
.rxmode = {
.max_rx_pkt_len = ETHER_MAX_LEN,
.split_hdr_size = 0,
.header_split = 0,
.hw_ip_checksum = 1,
.hw_vlan_filter = 0,
.jumbo_frame = 0,
.hw_strip_crc = 1,
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
.rx_adv_conf.rss_conf.rss_key = NULL,
.rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP,
};
ret = rte_eth_dev_configure(port_id, 1, 1, &port_conf);
if (ret < 0)
return -1;
// 分配mbuf内存池
struct rte_mempool *mp;
mp = rte_pktmbuf_pool_create("MBUF_POOL", NUM_MBUFS, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, SOCKET_ID_ANY);
if (mp == NULL)
return -1;
// 创建一个空的mbuf,用于存储填充后的数据包
struct rte_mbuf *pkt_mbuf;
pkt_mbuf = rte_pktmbuf_alloc(mp);
if (pkt_mbuf == NULL)
return -1;
// 在已有的mbuf缓冲区前面填充以太网头部
struct ether_hdr *eth_hdr;
eth_hdr = (struct ether_hdr *)rte_pktmbuf_prepend(mbuf1, sizeof(struct ether_hdr)); // 将数据指针移动到已有数据之前
memcpy(ð_hdr->d_addr, &dest_mac.addr_bytes, ETHER_ADDR_LEN); // 目标MAC地址
eth_hdr->ether_type = htons(ETHER_TYPE_IPv4); // 协议类型
// 在已有的mbuf缓冲区前面填充IP头部
struct ipv4_hdr *ip_hdr;
ip_hdr = (struct ipv4_hdr *)rte_pktmbuf_prepend(mbuf1, sizeof(struct ipv4_hdr)); // 将数据指针移动到已有数据之前
ip_hdr->version_ihl = IP_VHL_DEF; // 版本号和首部长度
ip_hdr->type_of_service= 0; // 服务类型,这里为0表示普通数据包
ip_hdr->total_length = htons(mbuf1->data_len); // 总长度,包括IP头部和UDP头部
ip_hdr->packet_id = 0; // 包标识符,这里为0表示未使用
ip_hdr->fragment_offset= 0; // 分片偏移量,这里为0表示未分片
ip_hdr->time_to_live = IP_DEFTTL; // 生存时间,默认为64
ip_hdr->next_proto_id = IPPROTO_UDP; // 协议类型,这里为UDP协议
ip_hdr->src_addr = htonl(IPv4(192,168,1,100)); // 源IP地址
ip_hdr->dst_addr = htonl(IPv4(192,168,1,200)); // 目标IP地址
ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr); // 计算校验和
// 在已有的mbuf缓冲区前面填充UDP头部
struct udp_hdr *udp_hdr;
udp_hdr = (struct udp_hdr *)rte_pktmbuf_prepend(mbuf1, sizeof(struct udp_hdr)); // 将数据指针移动到已有数据之前
udp_hdr->src_port = htons(12345); // 源端口号,这里随意设定一个值
udp_hdr->dst_port = htons(54321); // 目标端口号,这里随意设定一个值
udp_hdr->dgram_len= htons(mbuf1->data_len - sizeof(struct ipv4_hdr)); // 数据报文长度,包括UDP头部和应用层数据(这里不需要填充)
udp_hdr->dgram_cksum=0; // 数据报文校验和,这里不需要计算
// 将已有的mbuf缓冲区链接到新创建的mbuf上,并设置pkt_mbuf为发送队列中唯一的mbuf
rte_pktmbuf_chain(pkt_mbuf, mbuf1);
// 发送数据包
ret = rte_eth_tx_burst(port_id, 0, &pkt_mbuf, 1);
if (ret < 1)
return -1;
return 0;
}
上述代码假设使用的是DPDK的第一个物理端口,目标MAC地址为00:11:22:33:44:55
,源IP地址为192.168.1.100
,目标IP地址为192.168.1.200
。发送的UDP数据包源端口号为12345,目标端口号为54321。
在实际使用时还需要进行一些配置和错误处理等操作,请注意参考官方文档进行开发。