【发布时间】:2020-10-25 14:44:34
【问题描述】:
我用以下代码构造 DPDK 数据包:
#define PKG_GEN_COUNT 1
#define EIU_HEADER_LEN 42
#define ETHERNET_HEADER_LEN 14
#define IP_DEFTTL 64 /* from RFC 1340. */
#define IP_VERSION 0x40
#define IP_HDRLEN 0x05 /* default IP header length == five 32-bits words. */
#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
#define MEGA_JOB_GET 0x2
#define MEGA_JOB_SET 0x3
#define MEGA_END_MARK_LEN 2
#define PROTOCOL_TYPE_LEN 2U
#define KEY_LEN 8
#define VAL_LEN 8
#define PROTOCOL_KEYLEN_LEN 2U
#define PROTOCOL_VALLEN_LEN 4U
#define PROTOCOL_HEADER_LEN 8U
struct rte_mbuf *tx_bufs_pt[PKG_GEN_COUNT];
struct rte_ether_hdr *ethh;
struct rte_ipv4_hdr *ip_hdr;
struct rte_udp_hdr *udph;
for (int i = 0; i < PKG_GEN_COUNT; i++) {
struct rte_mbuf *pkt = (struct rte_mbuf *)rte_pktmbuf_alloc(
(struct rte_mempool *)send_mbuf_pool);
if (pkt == NULL)
rte_exit(EXIT_FAILURE,
"Cannot alloc storage memory in port %" PRIu16 "\n",
port);
pkt->data_len = 1484;
pkt->nb_segs = 1; // nb_segs
pkt->pkt_len = pkt->data_len;
pkt->ol_flags = PKT_TX_IPV4; // ol_flags
pkt->vlan_tci = 0; // vlan_tci
pkt->vlan_tci_outer = 0; // vlan_tci_outer
pkt->l2_len = sizeof(struct rte_ether_hdr);
pkt->l3_len = sizeof(struct rte_ipv4_hdr);
ethh = (struct rte_ether_hdr *)rte_pktmbuf_mtod(pkt, unsigned char *);
ethh->s_addr = S_Addr;
ethh->d_addr = D_Addr;
ethh->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4);
ip_hdr = (struct rte_ipv4_hdr *)((unsigned char *)ethh +
sizeof(struct rte_ether_hdr));
ip_hdr->version_ihl = IP_VHL_DEF;
ip_hdr->type_of_service = 0;
ip_hdr->fragment_offset = 0;
ip_hdr->time_to_live = IP_DEFTTL;
ip_hdr->next_proto_id = IPPROTO_UDP;
ip_hdr->packet_id = 0;
ip_hdr->total_length = rte_cpu_to_be_16(pktlen);
ip_hdr->src_addr = rte_cpu_to_be_32(IP_SRC_ADDR);
ip_hdr->dst_addr = rte_cpu_to_be_32(IP_DST_ADDR);
ip_hdr->hdr_checksum = rte_ipv4_cksum(ip_hdr);
udph = (struct rte_udp_hdr *)((unsigned char *)ip_hdr +
sizeof(struct rte_ipv4_hdr));
udph->src_port = 123;
udph->dst_port = 123;
udph->dgram_len =
rte_cpu_to_be_16((uint16_t)(pktlen - sizeof(struct rte_ether_hdr) -
sizeof(struct rte_ipv4_hdr)));
tx_bufs_pt[i] = pkt;
}
char *ptr = NULL;
uint64_t set_key = 1;
while (1) {
for (i = 0; i < PKG_GEN_COUNT; i++) {
/* Load request */
ptr = (char *)((char *)rte_pktmbuf_mtod(tx_bufs_pt[i], char *) +
EIU_HEADER_LEN);
tx_pkt_load(ptr, &set_key);
}
int nb_tx = rte_eth_tx_burst(port, queue_id, tx_bufs_pt, PKG_GEN_COUNT);
}
tx_pkt_load 函数填充 IP 数据包的内容。
static void tx_pkt_load(char *ptr, uint64_t *start_set_key) {
uint64_t k, get_key, set_key = *start_set_key;
for (k = 0; k < number_packet_set[WORKLOAD_ID]; k++) {
*(uint16_t *)ptr = MEGA_JOB_SET;
ptr += sizeof(uint16_t);
*(uint16_t *)ptr = KEY_LEN;
ptr += sizeof(uint16_t);
*(uint32_t *)ptr = VALUE_LEN;
ptr += sizeof(uint32_t);
set_key++;
*(uint64_t *)(ptr) = set_key;
ptr += KEY_LEN;
*(uint64_t *)(ptr) = set_key + 1;
ptr += VALUE_LEN;
*(uint16_t *)ptr = MEGA_JOB_GET;
ptr += sizeof(uint16_t);
*(uint16_t *)ptr = KEY_LEN;
ptr += sizeof(uint16_t);
get_key = set_key;
*(uint64_t *)(ptr) = get_key;
ptr += KEY_LEN;
}
*start_set_key = set_key;
/* pkt ending mark */
*(uint16_t *)ptr = 0xFFFF;
}
在调用rte_eth_tx_burst 之前,我使用show_pkt 函数转储IP 包的内容。
void show_pkt(struct rte_mbuf *pkt) {
int pktlen = pkt->data_len - EIU_HEADER_LEN;
uint8_t *ptr = (uint8_t *)((uint8_t *)rte_pktmbuf_mtod(pkt, uint8_t *) +
EIU_HEADER_LEN);
while (*(uint16_t *)ptr != 0xFFFF) {
uint32_t key_len = *(uint16_t *)(ptr + PROTOCOL_TYPE_LEN);
if (*(uint16_t *)ptr == MEGA_JOB_GET) {
fprintf(
fp[sched_getcpu()], "GET\t%lu\n",
*(uint64_t *)(ptr + PROTOCOL_TYPE_LEN + PROTOCOL_KEYLEN_LEN));
ptr += PROTOCOL_TYPE_LEN + PROTOCOL_KEYLEN_LEN + key_len;
} else if (*(uint16_t *)ptr == MEGA_JOB_SET) {
uint32_t val_len =
*(uint16_t *)(ptr + PROTOCOL_TYPE_LEN + PROTOCOL_KEYLEN_LEN);
fprintf(fp[sched_getcpu()], "SET\t%lu\t%lu\n",
*(uint64_t *)(ptr + PROTOCOL_HEADER_LEN),
*(uint64_t *)(ptr + PROTOCOL_HEADER_LEN + key_len));
ptr += PROTOCOL_TYPE_LEN + PROTOCOL_KEYLEN_LEN +
PROTOCOL_VALLEN_LEN + key_len + val_len;
}
}
fprintf(fp[sched_getcpu()], "END_MARK: %04x \n", *(uint16_t *)ptr);
fprintf(fp[sched_getcpu()], "\n");
fflush(fp[sched_getcpu()]);
}
生成的文件显示预期的数据包内容。每个GET 与最后一个SET 的第一个参数具有相同的参数,GET 的参数应该是增量的。 SET 的第二个参数等于它的第一个参数加一个,SET 的参数也应该分别是递增的。
SET 82 83
GET 82
SET 83 84
GET 83
SET 84 85
GET 84
SET 85 86
GET 85
SET 86 87
GET 86
SET 87 88
GET 87
SET 88 89
GET 88
SET 89 90
GET 89
SET 90 91
GET 90
SET 91 92
GET 91
SET 92 93
GET 92
SET 93 94
GET 93
SET 94 95
GET 94
SET 95 96
GET 95
SET 96 97
GET 96
SET 97 98
GET 97
SET 98 99
GET 98
SET 99 100
GET 99
SET 100 101
GET 100
SET 101 102
GET 101
SET 102 103
GET 102
SET 103 104
GET 103
SET 104 105
GET 104
SET 105 106
GET 105
SET 106 107
GET 106
SET 107 108
GET 107
SET 108 109
GET 108
SET 109 110
GET 109
SET 110 111
GET 110
SET 111 112
GET 111
SET 112 113
GET 112
SET 113 114
GET 113
SET 114 115
GET 114
SET 115 116
GET 115
SET 116 117
GET 116
SET 117 118
GET 117
SET 118 119
GET 118
SET 119 120
GET 119
SET 120 121
GET 120
SET 121 122
GET 121
END_MARK: ffff
但是,当我使用tcpdump 捕获目标机器上收到的数据包时,捕获的数据包不包含预期的内容。我还尝试使用rte_eth_rx_burst 接收数据包并通过相同的功能show_pkt 转储数据包的内容。它显示与以下相同的结果。太奇怪了。
SET 82 83
GET 82
SET 83 84
GET 83
SET 84 85
GET 84
SET 85 86
GET 85
SET 86 87
GET 86
SET 87 88
GET 87
SET 88 89
GET 88
SET 89 90
GET 89
SET 90 91
GET 90
SET 91 92
GET 91
SET 92 93
GET 92
SET 93 94
GET 93
SET 94 95
GET 94
SET 95 96
GET 95
SET 96 97
GET 96
SET 97 98
GET 97
SET 98 99
GET 98
SET 99 100
GET 99
SET 100 101
GET 100
SET 101 102
GET 101
SET 102 103
GET 102
SET 103 104
GET 103
SET 104 105
GET 104
SET 105 106
GET 105
SET 106 107
GET 106
SET 107 108
GET 107
SET 108 109
GET 108
SET 109 110
GET 109
SET 110 111
GET 110
SET 111 112
GET 111
SET 112 113
GET 112
SET 73 74
GET 73
SET 74 75
GET 74
SET 75 76
GET 75
SET 76 77
GET 76
SET 77 78
GET 77
SET 78 79
GET 78
SET 79 80
GET 79
SET 80 81
GET 80
SET 81 82
GET 81
END_MARK: ffff
[更新]
通过rte_pktmbuf_dump 转储的packets 包含例外内容。而tcpdump 捕获的packets 很奇怪。
数据包的内容具有以下模式。
uint16_t (0x03)
uint16_t (0x08)
uint32_t (0x08)
uint64_t (x)
uint64_t (x + 1)
uint16_t (0x02)
uint16_t (0x8)
uint64_t (x)
x 应该在所有数据包中单调递增。 tcpdump捕获的第二个数据包不符合这个规律。起始x 是82,在数据包末尾,x 是81。
[更新]
rte_pktmbuf_dump转储的第二个数据包的一部分:
00000030: 00 00 2A 00 00 00 00 00 00 00 2B 00 00 00 00 00
...
000005C0: 08 00 51 00 00 00 00 00 00 00 FF FF
通过tcpdump捕获的第二个数据包的一部分:
0x0020: 0800 0000 5200 0000 0000 0000 5300 0000
...
0x05b0: 0200 0800 5100 0000 0000 0000 ffff
与rte_pktmbuf_dump转储的数据包的第0x32字节相比,tcpdump捕获的数据包的第0x24字节应该是2a。因为两个包的最后12个字节是一样的,也就是说两个包应该是一样的。
【问题讨论】:
-
看起来你正在一个小端机器上运行代码。这是真的?能不能暂时注释
show_pkt功能码,用rte_pktmbuf_dump转储包。您能否将内容与tcpdump -exi [nic]进行比较和分享? -
@VipinVarghese 是的。我在一个小端机器上运行代码。我尝试了您的建议并更新了我的问题。
-
请更新数据包转储和 tcpdump 结果。您共享的不是您想要的。
-
我无法从您当前的编辑中理解
0x03 0x08 0x08 x x+1 0x02是什么,是标头还是有效负载。所以请上传数据 -
@VipinVarghese 我使用
Ubuntu paste来共享数据包内容。packets这个词的超链接。该模式是为了方便您检查数据包内容。我想说的是,我用这种模式填充了 IP 数据包的有效负载。如果您仍然对此感到困惑,请忘记这一点并检查我的代码以找出数据包的内容。
标签: endianness dpdk