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