1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2023 Marvell. 3 */ 4 5 #include <rte_byteorder.h> 6 #include <rte_common.h> 7 #include <rte_cycles.h> 8 #include <rte_ether.h> 9 #include <rte_hexdump.h> 10 #include <rte_ip.h> 11 #include <rte_ip_frag.h> 12 #include <rte_mbuf.h> 13 #include <rte_mbuf_pool_ops.h> 14 #include <rte_os_shim.h> 15 #include <rte_random.h> 16 #include <rte_udp.h> 17 18 #include "test.h" 19 20 #define MAX_FLOWS (1024 * 32) 21 #define MAX_BKTS MAX_FLOWS 22 #define MAX_ENTRIES_PER_BKT 16 23 #define MAX_FRAGMENTS RTE_LIBRTE_IP_FRAG_MAX_FRAG 24 #define MIN_FRAGMENTS 2 25 #define MAX_PKTS (MAX_FLOWS * MAX_FRAGMENTS) 26 27 #define MAX_PKT_LEN 2048 28 #define MAX_TTL_MS (5 * MS_PER_S) 29 30 /* use RFC863 Discard Protocol */ 31 #define UDP_SRC_PORT 9 32 #define UDP_DST_PORT 9 33 34 /* use RFC5735 / RFC2544 reserved network test addresses */ 35 #define IP_SRC_ADDR(x) ((198U << 24) | (18 << 16) | (0 << 8) | (x)) 36 #define IP_DST_ADDR(x) ((198U << 24) | (18 << 16) | (1 << 15) | (x)) 37 38 /* 2001:0200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180) */ 39 static uint8_t ip6_addr[16] = {32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 40 #define IP6_VERSION 6 41 42 #define IP_DEFTTL 64 /* from RFC 1340. */ 43 44 static struct rte_ip_frag_tbl *frag_tbl; 45 static struct rte_mempool *pkt_pool; 46 static struct rte_mbuf *mbufs[MAX_FLOWS][MAX_FRAGMENTS]; 47 static uint8_t frag_per_flow[MAX_FLOWS]; 48 static uint32_t flow_cnt; 49 50 #define FILL_MODE_LINEAR 0 51 #define FILL_MODE_RANDOM 1 52 #define FILL_MODE_INTERLEAVED 2 53 54 static int 55 reassembly_test_setup(void) 56 { 57 uint64_t max_ttl_cyc = (MAX_TTL_MS * rte_get_timer_hz()) / 1E3; 58 59 frag_tbl = rte_ip_frag_table_create(MAX_BKTS, MAX_ENTRIES_PER_BKT, 60 MAX_BKTS * MAX_ENTRIES_PER_BKT, max_ttl_cyc, 61 rte_socket_id()); 62 if (frag_tbl == NULL) 63 return TEST_FAILED; 64 65 rte_mbuf_set_user_mempool_ops("ring_mp_mc"); 66 pkt_pool = rte_pktmbuf_pool_create( 67 "reassembly_perf_pool", MAX_FLOWS * MAX_FRAGMENTS, 0, 0, 68 RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()); 69 if (pkt_pool == NULL) { 70 printf("[%s] Failed to create pkt pool\n", __func__); 71 rte_ip_frag_table_destroy(frag_tbl); 72 return TEST_FAILED; 73 } 74 75 return TEST_SUCCESS; 76 } 77 78 static void 79 reassembly_test_teardown(void) 80 { 81 if (frag_tbl != NULL) 82 rte_ip_frag_table_destroy(frag_tbl); 83 84 rte_mempool_free(pkt_pool); 85 } 86 87 static void 88 randomize_array_positions(void **array, uint8_t sz) 89 { 90 void *tmp; 91 int i, j; 92 93 if (sz == 2) { 94 tmp = array[0]; 95 array[0] = array[1]; 96 array[1] = tmp; 97 } else { 98 for (i = sz - 1; i > 0; i--) { 99 j = rte_rand_max(i + 1); 100 tmp = array[i]; 101 array[i] = array[j]; 102 array[j] = tmp; 103 } 104 } 105 } 106 107 static void 108 reassembly_print_banner(const char *proto_str) 109 { 110 printf("+==============================================================" 111 "============================================+\n"); 112 printf("| %-32s| %-3s : %-58d|\n", proto_str, "Flow Count", MAX_FLOWS); 113 printf("+================+================+=============+=============+" 114 "========================+===================+\n"); 115 printf("%-17s%-17s%-14s%-14s%-25s%-20s\n", "| Fragment Order", 116 "| Fragments/Flow", "| Outstanding", "| Cycles/Flow", 117 "| Cycles/Fragment insert", "| Cycles/Reassembly |"); 118 printf("+================+================+=============+=============+" 119 "========================+===================+\n"); 120 } 121 122 static void 123 ipv4_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id, 124 uint8_t fill_mode) 125 { 126 struct rte_ether_hdr *eth_hdr; 127 struct rte_ipv4_hdr *ip_hdr; 128 struct rte_udp_hdr *udp_hdr; 129 uint16_t frag_len; 130 uint8_t i; 131 132 frag_len = MAX_PKT_LEN / nb_frags; 133 if (frag_len % 8) 134 frag_len = RTE_ALIGN_MUL_CEIL(frag_len, 8); 135 136 for (i = 0; i < nb_frags; i++) { 137 struct rte_mbuf *frag = mbuf[i]; 138 uint16_t frag_offset = 0; 139 uint32_t ip_cksum; 140 uint16_t pkt_len; 141 uint16_t *ptr16; 142 143 frag_offset = i * (frag_len / 8); 144 145 if (i == nb_frags - 1) 146 frag_len = MAX_PKT_LEN - (frag_len * (nb_frags - 1)); 147 else 148 frag_offset |= RTE_IPV4_HDR_MF_FLAG; 149 150 rte_pktmbuf_reset_headroom(frag); 151 eth_hdr = rte_pktmbuf_mtod(frag, struct rte_ether_hdr *); 152 ip_hdr = rte_pktmbuf_mtod_offset(frag, struct rte_ipv4_hdr *, 153 sizeof(struct rte_ether_hdr)); 154 udp_hdr = rte_pktmbuf_mtod_offset( 155 frag, struct rte_udp_hdr *, 156 sizeof(struct rte_ether_hdr) + 157 sizeof(struct rte_ipv4_hdr)); 158 159 rte_ether_unformat_addr("02:00:00:00:00:01", 160 ð_hdr->dst_addr); 161 rte_ether_unformat_addr("02:00:00:00:00:00", 162 ð_hdr->src_addr); 163 eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4); 164 165 pkt_len = frag_len; 166 /* 167 * Initialize UDP header. 168 */ 169 if (i == 0) { 170 udp_hdr->src_port = rte_cpu_to_be_16(UDP_SRC_PORT); 171 udp_hdr->dst_port = rte_cpu_to_be_16(UDP_DST_PORT); 172 udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len); 173 udp_hdr->dgram_cksum = 0; /* No UDP checksum. */ 174 } 175 176 /* 177 * Initialize IP header. 178 */ 179 pkt_len = (uint16_t)(pkt_len + sizeof(struct rte_ipv4_hdr)); 180 ip_hdr->version_ihl = RTE_IPV4_VHL_DEF; 181 ip_hdr->type_of_service = 0; 182 ip_hdr->fragment_offset = rte_cpu_to_be_16(frag_offset); 183 ip_hdr->time_to_live = IP_DEFTTL; 184 ip_hdr->next_proto_id = IPPROTO_UDP; 185 ip_hdr->packet_id = 186 rte_cpu_to_be_16((flow_id + 1) % UINT16_MAX); 187 ip_hdr->total_length = rte_cpu_to_be_16(pkt_len); 188 /* Using more than 32K flows will modify the 2nd octet of the IP. */ 189 ip_hdr->src_addr = rte_cpu_to_be_32(IP_SRC_ADDR(flow_id)); 190 ip_hdr->dst_addr = rte_cpu_to_be_32(IP_DST_ADDR(flow_id)); 191 192 /* 193 * Compute IP header checksum. 194 */ 195 ptr16 = (unaligned_uint16_t *)ip_hdr; 196 ip_cksum = 0; 197 ip_cksum += ptr16[0]; 198 ip_cksum += ptr16[1]; 199 ip_cksum += ptr16[2]; 200 ip_cksum += ptr16[3]; 201 ip_cksum += ptr16[4]; 202 ip_cksum += ptr16[6]; 203 ip_cksum += ptr16[7]; 204 ip_cksum += ptr16[8]; 205 ip_cksum += ptr16[9]; 206 207 /* 208 * Reduce 32 bit checksum to 16 bits and complement it. 209 */ 210 ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) + 211 (ip_cksum & 0x0000FFFF); 212 if (ip_cksum > 65535) 213 ip_cksum -= 65535; 214 ip_cksum = (~ip_cksum) & 0x0000FFFF; 215 if (ip_cksum == 0) 216 ip_cksum = 0xFFFF; 217 ip_hdr->hdr_checksum = (uint16_t)ip_cksum; 218 219 frag->data_len = sizeof(struct rte_ether_hdr) + pkt_len; 220 frag->pkt_len = frag->data_len; 221 frag->l2_len = sizeof(struct rte_ether_hdr); 222 frag->l3_len = sizeof(struct rte_ipv4_hdr); 223 } 224 225 if (fill_mode == FILL_MODE_RANDOM) 226 randomize_array_positions((void **)mbuf, nb_frags); 227 } 228 229 static uint8_t 230 get_rand_frags(uint8_t max_frag) 231 { 232 uint8_t frags = rte_rand_max(max_frag + 1); 233 234 return frags <= 1 ? MIN_FRAGMENTS : frags; 235 } 236 237 static int 238 ipv4_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag) 239 { 240 uint8_t nb_frag; 241 int i; 242 243 for (i = 0; i < MAX_FLOWS; i++) { 244 nb_frag = get_rand_frags(max_frag); 245 if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) < 246 0) 247 return TEST_FAILED; 248 ipv4_frag_fill_data(mbufs[i], nb_frag, i, fill_mode); 249 frag_per_flow[i] = nb_frag; 250 } 251 flow_cnt = i; 252 253 return TEST_SUCCESS; 254 } 255 256 static int 257 ipv4_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag) 258 { 259 int i; 260 261 for (i = 0; i < MAX_FLOWS; i++) { 262 if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) < 263 0) 264 return TEST_FAILED; 265 ipv4_frag_fill_data(mbufs[i], nb_frag, i, fill_mode); 266 frag_per_flow[i] = nb_frag; 267 } 268 flow_cnt = i; 269 270 return TEST_SUCCESS; 271 } 272 273 static void 274 ipv6_frag_fill_data(struct rte_mbuf **mbuf, uint8_t nb_frags, uint32_t flow_id, 275 uint8_t fill_mode) 276 { 277 struct ipv6_extension_fragment *frag_hdr; 278 struct rte_ether_hdr *eth_hdr; 279 struct rte_ipv6_hdr *ip_hdr; 280 struct rte_udp_hdr *udp_hdr; 281 uint16_t frag_len; 282 uint8_t i; 283 284 frag_len = MAX_PKT_LEN / nb_frags; 285 if (frag_len % 8) 286 frag_len = RTE_ALIGN_MUL_CEIL(frag_len, 8); 287 288 for (i = 0; i < nb_frags; i++) { 289 struct rte_mbuf *frag = mbuf[i]; 290 uint16_t frag_offset = 0; 291 uint16_t pkt_len; 292 293 frag_offset = i * (frag_len / 8); 294 frag_offset <<= 3; 295 if (i == nb_frags - 1) { 296 frag_len = MAX_PKT_LEN - (frag_len * (nb_frags - 1)); 297 frag_offset = RTE_IPV6_SET_FRAG_DATA(frag_offset, 0); 298 } else { 299 frag_offset = RTE_IPV6_SET_FRAG_DATA(frag_offset, 1); 300 } 301 302 rte_pktmbuf_reset_headroom(frag); 303 eth_hdr = rte_pktmbuf_mtod(frag, struct rte_ether_hdr *); 304 ip_hdr = rte_pktmbuf_mtod_offset(frag, struct rte_ipv6_hdr *, 305 sizeof(struct rte_ether_hdr)); 306 udp_hdr = rte_pktmbuf_mtod_offset( 307 frag, struct rte_udp_hdr *, 308 sizeof(struct rte_ether_hdr) + 309 sizeof(struct rte_ipv6_hdr) + 310 RTE_IPV6_FRAG_HDR_SIZE); 311 frag_hdr = rte_pktmbuf_mtod_offset( 312 frag, struct ipv6_extension_fragment *, 313 sizeof(struct rte_ether_hdr) + 314 sizeof(struct rte_ipv6_hdr)); 315 316 rte_ether_unformat_addr("02:00:00:00:00:01", 317 ð_hdr->dst_addr); 318 rte_ether_unformat_addr("02:00:00:00:00:00", 319 ð_hdr->src_addr); 320 eth_hdr->ether_type = rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6); 321 322 pkt_len = frag_len; 323 /* 324 * Initialize UDP header. 325 */ 326 if (i == 0) { 327 udp_hdr->src_port = rte_cpu_to_be_16(UDP_SRC_PORT); 328 udp_hdr->dst_port = rte_cpu_to_be_16(UDP_DST_PORT); 329 udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len); 330 udp_hdr->dgram_cksum = 0; /* No UDP checksum. */ 331 } 332 333 /* 334 * Initialize IP header. 335 */ 336 pkt_len = (uint16_t)(pkt_len + sizeof(struct rte_ipv6_hdr) + 337 RTE_IPV6_FRAG_HDR_SIZE); 338 ip_hdr->vtc_flow = rte_cpu_to_be_32(IP6_VERSION << 28); 339 ip_hdr->payload_len = 340 rte_cpu_to_be_16(pkt_len - sizeof(struct rte_ipv6_hdr)); 341 ip_hdr->proto = IPPROTO_FRAGMENT; 342 ip_hdr->hop_limits = IP_DEFTTL; 343 memcpy(ip_hdr->src_addr, ip6_addr, sizeof(ip_hdr->src_addr)); 344 memcpy(ip_hdr->dst_addr, ip6_addr, sizeof(ip_hdr->dst_addr)); 345 ip_hdr->src_addr[7] = (flow_id >> 16) & 0xf; 346 ip_hdr->src_addr[7] |= 0x10; 347 ip_hdr->src_addr[8] = (flow_id >> 8) & 0xff; 348 ip_hdr->src_addr[9] = flow_id & 0xff; 349 350 ip_hdr->dst_addr[7] = (flow_id >> 16) & 0xf; 351 ip_hdr->dst_addr[7] |= 0x20; 352 ip_hdr->dst_addr[8] = (flow_id >> 8) & 0xff; 353 ip_hdr->dst_addr[9] = flow_id & 0xff; 354 355 frag_hdr->next_header = IPPROTO_UDP; 356 frag_hdr->reserved = 0; 357 frag_hdr->frag_data = rte_cpu_to_be_16(frag_offset); 358 frag_hdr->id = rte_cpu_to_be_32(flow_id + 1); 359 360 frag->data_len = sizeof(struct rte_ether_hdr) + pkt_len; 361 frag->pkt_len = frag->data_len; 362 frag->l2_len = sizeof(struct rte_ether_hdr); 363 frag->l3_len = 364 sizeof(struct rte_ipv6_hdr) + RTE_IPV6_FRAG_HDR_SIZE; 365 } 366 367 if (fill_mode == FILL_MODE_RANDOM) 368 randomize_array_positions((void **)mbuf, nb_frags); 369 } 370 371 static int 372 ipv6_rand_frag_pkt_setup(uint8_t fill_mode, uint8_t max_frag) 373 { 374 uint8_t nb_frag; 375 int i; 376 377 for (i = 0; i < MAX_FLOWS; i++) { 378 nb_frag = get_rand_frags(max_frag); 379 if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) < 380 0) 381 return TEST_FAILED; 382 ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode); 383 frag_per_flow[i] = nb_frag; 384 } 385 flow_cnt = i; 386 387 return TEST_SUCCESS; 388 } 389 390 static int 391 ipv6_frag_pkt_setup(uint8_t fill_mode, uint8_t nb_frag) 392 { 393 int i; 394 395 for (i = 0; i < MAX_FLOWS; i++) { 396 if (rte_mempool_get_bulk(pkt_pool, (void **)mbufs[i], nb_frag) < 397 0) 398 return TEST_FAILED; 399 ipv6_frag_fill_data(mbufs[i], nb_frag, i, fill_mode); 400 frag_per_flow[i] = nb_frag; 401 } 402 flow_cnt = i; 403 404 return TEST_SUCCESS; 405 } 406 407 static void 408 frag_pkt_teardown(void) 409 { 410 uint32_t i; 411 412 for (i = 0; i < flow_cnt; i++) 413 rte_pktmbuf_free(mbufs[i][0]); 414 } 415 416 static void 417 reassembly_print_stats(int8_t nb_frags, uint8_t fill_order, 418 uint32_t outstanding, uint64_t cyc_per_flow, 419 uint64_t cyc_per_frag_insert, 420 uint64_t cyc_per_reassembly) 421 { 422 char frag_str[8], order_str[12]; 423 424 if (nb_frags > 0) 425 snprintf(frag_str, sizeof(frag_str), "%d", nb_frags); 426 else 427 snprintf(frag_str, sizeof(frag_str), "RANDOM"); 428 429 switch (fill_order) { 430 case FILL_MODE_LINEAR: 431 snprintf(order_str, sizeof(order_str), "LINEAR"); 432 break; 433 case FILL_MODE_RANDOM: 434 snprintf(order_str, sizeof(order_str), "RANDOM"); 435 break; 436 case FILL_MODE_INTERLEAVED: 437 snprintf(order_str, sizeof(order_str), "INTERLEAVED"); 438 break; 439 default: 440 break; 441 } 442 443 printf("| %-14s | %-14s | %-11d | %-11" PRIu64 " | %-22" PRIu64 444 " | %-17" PRIu64 " |\n", 445 order_str, frag_str, outstanding, cyc_per_flow, 446 cyc_per_frag_insert, cyc_per_reassembly); 447 printf("+================+================+=============+=============+" 448 "========================+===================+\n"); 449 } 450 451 static void 452 join_array(struct rte_mbuf **dest_arr, struct rte_mbuf **src_arr, 453 uint8_t offset, uint8_t sz) 454 { 455 int i, j; 456 457 for (i = offset, j = 0; j < sz; i++, j++) 458 dest_arr[i] = src_arr[j]; 459 } 460 461 static int 462 ipv4_reassembly_perf(int8_t nb_frags, uint8_t fill_order) 463 { 464 struct rte_ip_frag_death_row death_row; 465 uint64_t total_reassembled_cyc = 0; 466 uint64_t total_empty_cyc = 0; 467 uint64_t tstamp, flow_tstamp; 468 uint64_t frag_processed = 0; 469 uint64_t total_cyc = 0; 470 uint32_t i, j; 471 472 for (i = 0; i < flow_cnt; i++) { 473 struct rte_mbuf *buf_out = NULL; 474 uint8_t reassembled = 0; 475 476 flow_tstamp = rte_rdtsc_precise(); 477 for (j = 0; j < frag_per_flow[i]; j++) { 478 struct rte_mbuf *buf = mbufs[i][j]; 479 struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 480 buf, struct rte_ipv4_hdr *, buf->l2_len); 481 482 tstamp = rte_rdtsc_precise(); 483 buf_out = rte_ipv4_frag_reassemble_packet( 484 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr); 485 486 if (buf_out == NULL) { 487 total_empty_cyc += rte_rdtsc_precise() - tstamp; 488 frag_processed++; 489 continue; 490 } else { 491 /*Packet out*/ 492 total_reassembled_cyc += 493 rte_rdtsc_precise() - tstamp; 494 reassembled = 1; 495 } 496 } 497 total_cyc += rte_rdtsc_precise() - flow_tstamp; 498 if (!reassembled || buf_out->nb_segs != frag_per_flow[i]) 499 return TEST_FAILED; 500 memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS); 501 mbufs[i][0] = buf_out; 502 } 503 504 reassembly_print_stats(nb_frags, fill_order, 0, total_cyc / flow_cnt, 505 total_empty_cyc / frag_processed, 506 total_reassembled_cyc / flow_cnt); 507 508 return TEST_SUCCESS; 509 } 510 511 static int 512 ipv4_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order, 513 uint32_t outstanding) 514 { 515 struct rte_ip_frag_death_row death_row; 516 uint64_t total_reassembled_cyc = 0; 517 uint64_t total_empty_cyc = 0; 518 uint64_t tstamp, flow_tstamp; 519 uint64_t frag_processed = 0; 520 uint64_t total_cyc = 0; 521 uint32_t i, j, k; 522 523 k = outstanding; 524 /* Insert outstanding fragments */ 525 for (i = 0; k && (i < flow_cnt); i++) { 526 struct rte_mbuf *buf_out = NULL; 527 528 flow_tstamp = rte_rdtsc_precise(); 529 for (j = frag_per_flow[i] - 1; j > 0; j--) { 530 struct rte_mbuf *buf = mbufs[i][j]; 531 struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 532 buf, struct rte_ipv4_hdr *, buf->l2_len); 533 534 tstamp = rte_rdtsc_precise(); 535 buf_out = rte_ipv4_frag_reassemble_packet( 536 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr); 537 total_empty_cyc += rte_rdtsc_precise() - tstamp; 538 frag_processed++; 539 if (buf_out != NULL) 540 return TEST_FAILED; 541 542 k--; 543 } 544 frag_per_flow[i] = 1; 545 } 546 547 for (i = 0; i < flow_cnt; i++) { 548 struct rte_mbuf *buf_out = NULL; 549 uint8_t reassembled = 0; 550 551 flow_tstamp = rte_rdtsc_precise(); 552 for (j = 0; j < frag_per_flow[i]; j++) { 553 struct rte_mbuf *buf = mbufs[i][j]; 554 struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 555 buf, struct rte_ipv4_hdr *, buf->l2_len); 556 557 tstamp = rte_rdtsc_precise(); 558 buf_out = rte_ipv4_frag_reassemble_packet( 559 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr); 560 561 if (buf_out == NULL) { 562 total_empty_cyc += rte_rdtsc_precise() - tstamp; 563 frag_processed++; 564 continue; 565 } else { 566 /*Packet out*/ 567 total_reassembled_cyc += 568 rte_rdtsc_precise() - tstamp; 569 reassembled = 1; 570 } 571 } 572 total_cyc += rte_rdtsc_precise() - flow_tstamp; 573 if (!reassembled) 574 return TEST_FAILED; 575 memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS); 576 mbufs[i][0] = buf_out; 577 } 578 579 reassembly_print_stats(nb_frags, fill_order, outstanding, 580 total_cyc / flow_cnt, 581 total_empty_cyc / frag_processed, 582 total_reassembled_cyc / flow_cnt); 583 584 return TEST_SUCCESS; 585 } 586 587 static int 588 ipv4_reassembly_interleaved_flows_perf(uint8_t nb_frags) 589 { 590 struct rte_ip_frag_death_row death_row; 591 uint64_t total_reassembled_cyc = 0; 592 uint64_t total_empty_cyc = 0; 593 uint64_t tstamp, flow_tstamp; 594 uint64_t frag_processed = 0; 595 uint64_t total_cyc = 0; 596 uint32_t i, j; 597 598 for (i = 0; i < flow_cnt; i += 4) { 599 struct rte_mbuf *buf_out[4] = {NULL}; 600 uint8_t reassembled = 0; 601 uint8_t nb_frags = 0; 602 uint8_t prev = 0; 603 604 for (j = 0; j < 4; j++) 605 nb_frags += frag_per_flow[i + j]; 606 607 struct rte_mbuf *buf_arr[nb_frags]; 608 for (j = 0; j < 4; j++) { 609 join_array(buf_arr, mbufs[i + j], prev, 610 frag_per_flow[i + j]); 611 prev += frag_per_flow[i + j]; 612 } 613 randomize_array_positions((void **)buf_arr, nb_frags); 614 flow_tstamp = rte_rdtsc_precise(); 615 for (j = 0; j < nb_frags; j++) { 616 struct rte_mbuf *buf = buf_arr[j]; 617 struct rte_ipv4_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 618 buf, struct rte_ipv4_hdr *, buf->l2_len); 619 620 tstamp = rte_rdtsc_precise(); 621 buf_out[reassembled] = rte_ipv4_frag_reassemble_packet( 622 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr); 623 624 if (buf_out[reassembled] == NULL) { 625 total_empty_cyc += rte_rdtsc_precise() - tstamp; 626 frag_processed++; 627 continue; 628 } else { 629 /*Packet out*/ 630 total_reassembled_cyc += 631 rte_rdtsc_precise() - tstamp; 632 reassembled++; 633 } 634 } 635 total_cyc += rte_rdtsc_precise() - flow_tstamp; 636 if (reassembled != 4) 637 return TEST_FAILED; 638 for (j = 0; j < 4; j++) { 639 memset(mbufs[i + j], 0, 640 sizeof(struct rte_mbuf *) * MAX_FRAGMENTS); 641 mbufs[i + j][0] = buf_out[j]; 642 } 643 } 644 645 reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0, 646 total_cyc / flow_cnt, 647 total_empty_cyc / frag_processed, 648 total_reassembled_cyc / flow_cnt); 649 650 return TEST_SUCCESS; 651 } 652 653 static int 654 ipv6_reassembly_perf(int8_t nb_frags, uint8_t fill_order) 655 { 656 struct rte_ip_frag_death_row death_row; 657 uint64_t total_reassembled_cyc = 0; 658 uint64_t total_empty_cyc = 0; 659 uint64_t tstamp, flow_tstamp; 660 uint64_t frag_processed = 0; 661 uint64_t total_cyc = 0; 662 uint32_t i, j; 663 664 for (i = 0; i < flow_cnt; i++) { 665 struct rte_mbuf *buf_out = NULL; 666 uint8_t reassembled = 0; 667 668 flow_tstamp = rte_rdtsc_precise(); 669 for (j = 0; j < frag_per_flow[i]; j++) { 670 struct rte_mbuf *buf = mbufs[i][j]; 671 struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 672 buf, struct rte_ipv6_hdr *, buf->l2_len); 673 struct ipv6_extension_fragment *frag_hdr = 674 rte_pktmbuf_mtod_offset( 675 buf, struct ipv6_extension_fragment *, 676 buf->l2_len + 677 sizeof(struct rte_ipv6_hdr)); 678 679 tstamp = rte_rdtsc_precise(); 680 buf_out = rte_ipv6_frag_reassemble_packet( 681 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr, 682 frag_hdr); 683 684 if (buf_out == NULL) { 685 total_empty_cyc += rte_rdtsc_precise() - tstamp; 686 frag_processed++; 687 continue; 688 } else { 689 /*Packet out*/ 690 total_reassembled_cyc += 691 rte_rdtsc_precise() - tstamp; 692 reassembled = 1; 693 } 694 } 695 total_cyc += rte_rdtsc_precise() - flow_tstamp; 696 if (!reassembled || buf_out->nb_segs != frag_per_flow[i]) 697 return TEST_FAILED; 698 memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS); 699 mbufs[i][0] = buf_out; 700 } 701 702 reassembly_print_stats(nb_frags, fill_order, 0, total_cyc / flow_cnt, 703 total_empty_cyc / frag_processed, 704 total_reassembled_cyc / flow_cnt); 705 706 return TEST_SUCCESS; 707 } 708 709 static int 710 ipv6_outstanding_reassembly_perf(int8_t nb_frags, uint8_t fill_order, 711 uint32_t outstanding) 712 { 713 struct rte_ip_frag_death_row death_row; 714 uint64_t total_reassembled_cyc = 0; 715 uint64_t total_empty_cyc = 0; 716 uint64_t tstamp, flow_tstamp; 717 uint64_t frag_processed = 0; 718 uint64_t total_cyc = 0; 719 uint32_t i, j, k; 720 721 k = outstanding; 722 /* Insert outstanding fragments */ 723 for (i = 0; k && (i < flow_cnt); i++) { 724 struct rte_mbuf *buf_out = NULL; 725 726 flow_tstamp = rte_rdtsc_precise(); 727 for (j = frag_per_flow[i] - 1; j > 0; j--) { 728 struct rte_mbuf *buf = mbufs[i][j]; 729 struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 730 buf, struct rte_ipv6_hdr *, buf->l2_len); 731 struct ipv6_extension_fragment *frag_hdr = 732 rte_pktmbuf_mtod_offset( 733 buf, struct ipv6_extension_fragment *, 734 buf->l2_len + 735 sizeof(struct rte_ipv6_hdr)); 736 737 tstamp = rte_rdtsc_precise(); 738 buf_out = rte_ipv6_frag_reassemble_packet( 739 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr, 740 frag_hdr); 741 total_empty_cyc += rte_rdtsc_precise() - tstamp; 742 frag_processed++; 743 744 if (buf_out != NULL) 745 return TEST_FAILED; 746 747 k--; 748 } 749 frag_per_flow[i] = 1; 750 } 751 752 for (i = 0; i < flow_cnt; i++) { 753 struct rte_mbuf *buf_out = NULL; 754 uint8_t reassembled = 0; 755 756 flow_tstamp = rte_rdtsc_precise(); 757 for (j = 0; j < frag_per_flow[i]; j++) { 758 struct rte_mbuf *buf = mbufs[i][j]; 759 struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 760 buf, struct rte_ipv6_hdr *, buf->l2_len); 761 struct ipv6_extension_fragment *frag_hdr = 762 rte_pktmbuf_mtod_offset( 763 buf, struct ipv6_extension_fragment *, 764 buf->l2_len + 765 sizeof(struct rte_ipv6_hdr)); 766 767 tstamp = rte_rdtsc_precise(); 768 buf_out = rte_ipv6_frag_reassemble_packet( 769 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr, 770 frag_hdr); 771 772 if (buf_out == NULL) { 773 total_empty_cyc += rte_rdtsc_precise() - tstamp; 774 frag_processed++; 775 continue; 776 } else { 777 /*Packet out*/ 778 total_reassembled_cyc += 779 rte_rdtsc_precise() - tstamp; 780 reassembled = 1; 781 } 782 } 783 total_cyc += rte_rdtsc_precise() - flow_tstamp; 784 if (!reassembled) 785 return TEST_FAILED; 786 memset(mbufs[i], 0, sizeof(struct rte_mbuf *) * MAX_FRAGMENTS); 787 mbufs[i][0] = buf_out; 788 } 789 790 reassembly_print_stats(nb_frags, fill_order, outstanding, 791 total_cyc / flow_cnt, 792 total_empty_cyc / frag_processed, 793 total_reassembled_cyc / flow_cnt); 794 795 return TEST_SUCCESS; 796 } 797 798 static int 799 ipv6_reassembly_interleaved_flows_perf(int8_t nb_frags) 800 { 801 struct rte_ip_frag_death_row death_row; 802 uint64_t total_reassembled_cyc = 0; 803 uint64_t total_empty_cyc = 0; 804 uint64_t tstamp, flow_tstamp; 805 uint64_t frag_processed = 0; 806 uint64_t total_cyc = 0; 807 uint32_t i, j; 808 809 for (i = 0; i < flow_cnt; i += 4) { 810 struct rte_mbuf *buf_out[4] = {NULL}; 811 uint8_t reassembled = 0; 812 uint8_t nb_frags = 0; 813 uint8_t prev = 0; 814 815 for (j = 0; j < 4; j++) 816 nb_frags += frag_per_flow[i + j]; 817 818 struct rte_mbuf *buf_arr[nb_frags]; 819 for (j = 0; j < 4; j++) { 820 join_array(buf_arr, mbufs[i + j], prev, 821 frag_per_flow[i + j]); 822 prev += frag_per_flow[i + j]; 823 } 824 randomize_array_positions((void **)buf_arr, nb_frags); 825 flow_tstamp = rte_rdtsc_precise(); 826 for (j = 0; j < nb_frags; j++) { 827 struct rte_mbuf *buf = buf_arr[j]; 828 struct rte_ipv6_hdr *ip_hdr = rte_pktmbuf_mtod_offset( 829 buf, struct rte_ipv6_hdr *, buf->l2_len); 830 struct ipv6_extension_fragment *frag_hdr = 831 rte_pktmbuf_mtod_offset( 832 buf, struct ipv6_extension_fragment *, 833 buf->l2_len + 834 sizeof(struct rte_ipv6_hdr)); 835 836 tstamp = rte_rdtsc_precise(); 837 buf_out[reassembled] = rte_ipv6_frag_reassemble_packet( 838 frag_tbl, &death_row, buf, flow_tstamp, ip_hdr, 839 frag_hdr); 840 841 if (buf_out[reassembled] == NULL) { 842 total_empty_cyc += rte_rdtsc_precise() - tstamp; 843 frag_processed++; 844 continue; 845 } else { 846 /*Packet out*/ 847 total_reassembled_cyc += 848 rte_rdtsc_precise() - tstamp; 849 reassembled++; 850 } 851 } 852 total_cyc += rte_rdtsc_precise() - flow_tstamp; 853 if (reassembled != 4) 854 return TEST_FAILED; 855 for (j = 0; j < 4; j++) { 856 memset(mbufs[i + j], 0, 857 sizeof(struct rte_mbuf *) * MAX_FRAGMENTS); 858 mbufs[i + j][0] = buf_out[j]; 859 } 860 } 861 862 reassembly_print_stats(nb_frags, FILL_MODE_INTERLEAVED, 0, 863 total_cyc / flow_cnt, 864 total_empty_cyc / frag_processed, 865 total_reassembled_cyc / flow_cnt); 866 867 return TEST_SUCCESS; 868 } 869 870 static int 871 ipv4_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding) 872 { 873 int rc; 874 875 if (nb_frags > 0) 876 rc = ipv4_frag_pkt_setup(fill_order, nb_frags); 877 else 878 rc = ipv4_rand_frag_pkt_setup(fill_order, MAX_FRAGMENTS); 879 880 if (rc) 881 return rc; 882 883 if (outstanding) 884 rc = ipv4_outstanding_reassembly_perf(nb_frags, fill_order, 885 outstanding); 886 else if (fill_order == FILL_MODE_INTERLEAVED) 887 rc = ipv4_reassembly_interleaved_flows_perf(nb_frags); 888 else 889 rc = ipv4_reassembly_perf(nb_frags, fill_order); 890 891 frag_pkt_teardown(); 892 893 return rc; 894 } 895 896 static int 897 ipv6_reassembly_test(int8_t nb_frags, uint8_t fill_order, uint32_t outstanding) 898 { 899 int rc; 900 901 if (nb_frags > 0) 902 rc = ipv6_frag_pkt_setup(fill_order, nb_frags); 903 else 904 rc = ipv6_rand_frag_pkt_setup(fill_order, MAX_FRAGMENTS); 905 906 if (rc) 907 return rc; 908 909 if (outstanding) 910 rc = ipv6_outstanding_reassembly_perf(nb_frags, fill_order, 911 outstanding); 912 else if (fill_order == FILL_MODE_INTERLEAVED) 913 rc = ipv6_reassembly_interleaved_flows_perf(nb_frags); 914 else 915 rc = ipv6_reassembly_perf(nb_frags, fill_order); 916 917 frag_pkt_teardown(); 918 919 return rc; 920 } 921 922 static int 923 test_reassembly_perf(void) 924 { 925 int8_t nb_fragments[] = {2, 3, MAX_FRAGMENTS, -1 /* Random */}; 926 uint8_t order_type[] = {FILL_MODE_LINEAR, FILL_MODE_RANDOM}; 927 uint32_t outstanding[] = {100, 500, 1000, 2000, 3000}; 928 uint32_t i, j; 929 int rc; 930 931 rc = reassembly_test_setup(); 932 if (rc) 933 return rc; 934 935 reassembly_print_banner("IPV4"); 936 /* Test variable fragment count and ordering. */ 937 for (i = 0; i < RTE_DIM(nb_fragments); i++) { 938 for (j = 0; j < RTE_DIM(order_type); j++) { 939 rc = ipv4_reassembly_test(nb_fragments[i], 940 order_type[j], 0); 941 if (rc) 942 return rc; 943 } 944 } 945 946 /* Test outstanding fragments in the table. */ 947 for (i = 0; i < RTE_DIM(outstanding); i++) { 948 rc = ipv4_reassembly_test(2, 0, outstanding[i]); 949 if (rc) 950 return rc; 951 } 952 for (i = 0; i < RTE_DIM(outstanding); i++) { 953 rc = ipv4_reassembly_test(MAX_FRAGMENTS, 0, outstanding[i]); 954 if (rc) 955 return rc; 956 } 957 958 /* Test interleaved flow reassembly perf */ 959 for (i = 0; i < RTE_DIM(nb_fragments); i++) { 960 rc = ipv4_reassembly_test(nb_fragments[i], 961 FILL_MODE_INTERLEAVED, 0); 962 if (rc) 963 return rc; 964 } 965 printf("\n"); 966 reassembly_print_banner("IPV6"); 967 /* Test variable fragment count and ordering. */ 968 for (i = 0; i < RTE_DIM(nb_fragments); i++) { 969 for (j = 0; j < RTE_DIM(order_type); j++) { 970 rc = ipv6_reassembly_test(nb_fragments[i], 971 order_type[j], 0); 972 if (rc) 973 return rc; 974 } 975 } 976 977 /* Test outstanding fragments in the table. */ 978 for (i = 0; i < RTE_DIM(outstanding); i++) { 979 rc = ipv6_reassembly_test(2, 0, outstanding[i]); 980 if (rc) 981 return rc; 982 } 983 984 for (i = 0; i < RTE_DIM(outstanding); i++) { 985 rc = ipv6_reassembly_test(MAX_FRAGMENTS, 0, outstanding[i]); 986 if (rc) 987 return rc; 988 } 989 990 /* Test interleaved flow reassembly perf */ 991 for (i = 0; i < RTE_DIM(nb_fragments); i++) { 992 rc = ipv6_reassembly_test(nb_fragments[i], 993 FILL_MODE_INTERLEAVED, 0); 994 if (rc) 995 return rc; 996 } 997 reassembly_test_teardown(); 998 999 return TEST_SUCCESS; 1000 } 1001 1002 REGISTER_PERF_TEST(reassembly_perf_autotest, test_reassembly_perf); 1003