相关代码:DPDK_Learning/UDP_transmit at main · mfdycs/DPDK_Learning (github.com)
DPDK启动逻辑框架可以参考 接收UDP数据
定义网络信息
#define ENABLE_SEND 1
#define ENABLE_ARP 1
// 发送数据需要的网络信息, 先不考虑传参
#if ENABLE_SEND
static uint32_t gSrcIp;
static uint32_t gDstIp;
static uint8_t gSrcMac[RTE_ETHER_ADDR_LEN];
static uint8_t gDstMac[RTE_ETHER_ADDR_LEN];
static uint16_t gSrcPort;
static uint16_t gDstPort;
#endif
启动发送队列
// 配置网卡信息
const int num_tx_queues = 1; // 发送队列网卡数量
struct rte_eth_conf port_conf = port_conf_default;
#if ENABLE_SEND
// 启动tx队列
struct rte_eth_txconf txq_conf = dev_info.default_txconf;
// 修改tx对应负载:把发送大小设置为接收大小
txq_conf.offloads = port_conf.rxmode.offloads;
// rte_eth_tx_queue_setup(port_id, tx_queue_id, nb_rx_desc, socket_id, tx_conf);
ret = rte_eth_tx_queue_setup(DPDK_PortID, 0, 128, rte_eth_dev_socket_id(DPDK_PortID), &txq_conf);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");
}
#endif
发送数据
从 mempool 里面获取到 mbuf,mbuf是内存池中的最小单元
UDP首部长度为42字节:14(eth) + 20(ip) + 8(udp)
static struct rte_mbuf* ng_send(struct rte_mempool *mbuf_pool, unsigned char* data, uint16_t length)
{
struct rte_mbuf* mbuf = rte_pktmbuf_alloc(mbuf_pool);
if (!mbuf) {
rte_exit(EXIT_FAILURE, "Error with EAL init\n");
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
uint8_t *pktdata = rte_pktmbuf_mtod(mbuf, uint8_t*);
ng_encode_udp_pkt(pktdata, data, total_len);
return mbuf;
}
封装UDP数据
UDP数据头部信息:
以太网协议头:
IP协议头:
// encode udp pkt
static int ng_encode_udp_pkt(uint8_t *msg, unsigned char* data, uint16_t total_len)
{
// 1. ethhdr
struct rte_ether_hdr* eth = (struct rte_ether_hdr*)msg;
rte_memcpy(eth->s_addr.addr_bytes, gSrcMac, RTE_ETHER_ADDR_LEN);
rte_memcpy(eth->d_addr.addr_bytes, gDstMac, RTE_ETHER_ADDR_LEN);
eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);
// 2. iphdr
struct rte_ipv4_hdr* ip = (struct rte_ipv4_hdr*)(msg + sizeof(struct rte_ether_hdr));
ip->version_ihl = 0x54; // 版本+首部长度信息, 网络字节序
ip->type_of_service = 0;
ip->total_length = htons(total_len - sizeof(struct rte_ether_hdr));
ip->packet_id = 0; // 16位位标识
ip->fragment_offset = 0; // 3位标识+13位片位移
ip->time_to_live = 64;
ip->next_proto_id = IPPROTO_UDP;
ip->src_addr = gSrcIp;
ip->dst_addr = gDstIp;
ip->hdr_checksum = 0; // 先置0, 因为会参与计算
ip->hdr_checksum = rte_ipv4_cksum(ip);
// 3. udphdr
struct rte_udp_hdr* udp = (struct rte_udp_hdr*)(msg + sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr));
udp->src_port = gSrcPort;
udp->dst_port = gDstPort;
uint16_t udplen = total_len - sizeof(struct rte_ether_hdr) - sizeof(struct rte_ipv4_hdr);
udp->dgram_len = htons(udplen);
rte_memcpy((uint8_t*)(udp + 1), data, udplen);
udp->dgram_cksum = 0;
udp->dgram_cksum = rte_ipv4_udptcp_cksum(ip, udp);
// 4. print
struct in_addr addr;
addr.s_addr = gSrcIp;
printf(" --> src: %s:%d, ", inet_ntoa(addr), ntohs(gSrcPort));
addr.s_addr = gDstIp;
printf("dst: %s:%d\n", inet_ntoa(addr), ntohs(gDstPort));
return 0;
}
static struct rte_mbuf* ng_send(struct rte_mempool *mbuf_pool, unsigned char* data, uint16_t length)
{
const unsigned total_len = length + 42;
struct rte_mbuf* mbuf = rte_pktmbuf_alloc(mbuf_pool);
if (!mbuf) {
rte_exit(EXIT_FAILURE, "Error with EAL init\n");
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
uint8_t *pktdata = rte_pktmbuf_mtod(mbuf, uint8_t*);
ng_encode_udp_pkt(pktdata, data, total_len);
return mbuf;
}