☰
dpdk实现icmp
2026/10/15 19:18:27 网站建设 项目流程
协议中文层级(TCP/IP)层级(OSI)作用
Ethernet(以太网)以太网网络接口层数据链路层(L2)局域网内按 MAC 传帧
ARP地址解析协议网络接口层(常与 L3 交界)数据链路层 / 网络层之间IP → MAC 的地址解析
IP网际协议网络层网络层(L3)跨网络寻址、路由
ICMP网际控制报文协议网络层网络层(L3)差错报告、诊断(ping)
TCP传输控制协议传输层传输层(L4)可靠、面向连接
UDP用户数据报协议传输层传输层(L4)不可靠、无连接
DNS域名系统应用层应用层(L7)域名 ↔ IP 解析

ICMP(Internet Control Message Protocol,网际控制报文协议):用来传递控制信息,不携带用户数据。

图片来源:ICMP协议以及报文讲解(ICMP查询报文、ICMP差错报文)-CSDN博客

我们这里只实现了8,请求回显。

这里还有两个字段identifier和sequence number。

icmp类型:0 Reply 回显应答

代码:0

标识符identifier:原样回显

序列号:原样回显

ICMP 层:identifier 和 sequence 原样回显,这样双方才能匹配。

if( iphdr->next_proto_id == IPPROTO_ICMP) { struct rte_icmp_hdr *icmphdr = (struct rte_icmp_hdr *)(iphdr + 1); struct in_addr addr; addr.s_addr = iphdr->src_addr; printf("icmp src:%s, ",inet_ntoa(addr)); struct rte_mbuf *icmpbuf = fun_icmp_send(mbuf_pool,ehdr->s_addr.addr_bytes, iphdr->dst_addr,iphdr->src_addr,icmphdr->icmp_ident,icmphdr->icmp_seq_nb); rte_eth_tx_burst(gDpdkPortId,0,&icmpbuf,1); rte_pktmbuf_free(icmpbuf); rte_pktmbuf_free(mbufs[i]); }
static int fun_encode_icmp_pkt(uint8_t *msg,uint8_t *dst_mac,uint32_t sip,uint32_t dip, uint16_t id, uint16_t seqnb) { //printf("encode icmp pkt length:%d\n",total_len); // 1 ether hdr 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, dst_mac , RTE_ETHER_ADDR_LEN); eth->ether_type = htons(RTE_ETHER_TYPE_IPV4); // 2 ip hdr struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(msg+sizeof(struct rte_ether_hdr)); ip->version_ihl = 0x45; ip->type_of_service = 0; ip->total_length = htons(sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr)); printf("ip->total_length:%d\n",ntohs(ip->total_length)); ip->packet_id = 0; ip->fragment_offset = 0; ip->time_to_live = 64; ip->next_proto_id = IPPROTO_ICMP; ip->src_addr = sip; ip->dst_addr = dip; ip->hdr_checksum = 0; ip->hdr_checksum = rte_ipv4_cksum(ip); struct rte_icmp_hdr *icmphdr = (struct rte_icmp_hdr *)(msg+sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) ); icmphdr->icmp_type = RTE_IP_ICMP_ECHO_REPLY; icmphdr->icmp_code = 0; icmphdr->icmp_ident = id; icmphdr->icmp_seq_nb = seqnb; icmphdr->icmp_cksum = 0; icmphdr->icmp_cksum = fun_icmp_chechsum((uint16_t *)icmphdr,sizeof(struct rte_icmp_hdr)); return 0; } struct rte_mbuf *fun_icmp_send( struct rte_mempool *mbuf_pool,uint8_t *dst_mac,uint32_t sip,uint32_t dip, uint16_t id, uint16_t seqnb) { const unsigned total_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr); struct rte_mbuf *icmpmbuf = rte_pktmbuf_alloc(mbuf_pool); if(icmpmbuf == NULL){ rte_exit(EXIT_FAILURE,"icmp mbuf malloc fail\n"); } icmpmbuf->pkt_len = total_len; icmpmbuf->data_len = total_len; uint8_t *pktdata = rte_pktmbuf_mtod(icmpmbuf,uint8_t*); printf("fun_encode_icmp_pkt length:%d\n",total_len); fun_encode_icmp_pkt(pktdata, dst_mac, sip, dip, id, seqnb); return icmpmbuf; }

dpdk没有提供icmp的计算校验和的函数,需要自己实现。

static uint16_t fun_icmp_chechsum(uint16_t *addr,int count) { // register存储类说明符 // 建议编译器把这个变量放在 CPU 寄存器里,而不是内存里,以加快访问速度 register long sum =0; while(count > 1) { sum += *(unsigned short*)addr++; count -= 2; } if(count > 0) { sum += *(unsigned short *)addr; } while(sum >> 16) { sum = (sum & 0xffff) + (sum >> 16); } return ~sum; } unsigned short *)addr; } while(sum >> 16) { sum = (sum & 0xffff) + (sum >> 16); } return ~sum; }

文章参考<零声教育>的C/C++linux服务期高级架构系统教程学习:0voice · GitHub

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询