1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation. 3 * Copyright 2013-2014 6WIND S.A. 4 */ 5 6 #include <ctype.h> 7 #include <stdarg.h> 8 #include <errno.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <stdint.h> 13 #include <inttypes.h> 14 15 #include <sys/queue.h> 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <fcntl.h> 19 #include <unistd.h> 20 21 #include <rte_common.h> 22 #include <rte_byteorder.h> 23 #include <rte_debug.h> 24 #include <rte_log.h> 25 #include <rte_memory.h> 26 #include <rte_memcpy.h> 27 #include <rte_memzone.h> 28 #include <rte_launch.h> 29 #include <rte_bus.h> 30 #include <rte_eal.h> 31 #include <rte_per_lcore.h> 32 #include <rte_lcore.h> 33 #include <rte_branch_prediction.h> 34 #include <rte_mempool.h> 35 #include <rte_mbuf.h> 36 #include <rte_interrupts.h> 37 #include <rte_ether.h> 38 #include <rte_ethdev.h> 39 #include <rte_string_fns.h> 40 #include <rte_cycles.h> 41 #include <rte_flow.h> 42 #include <rte_mtr.h> 43 #include <rte_errno.h> 44 #ifdef RTE_NET_IXGBE 45 #include <rte_pmd_ixgbe.h> 46 #endif 47 #ifdef RTE_NET_I40E 48 #include <rte_pmd_i40e.h> 49 #endif 50 #ifdef RTE_NET_BNXT 51 #include <rte_pmd_bnxt.h> 52 #endif 53 #ifdef RTE_LIB_GRO 54 #include <rte_gro.h> 55 #endif 56 #include <rte_hexdump.h> 57 58 #include "testpmd.h" 59 #include "cmdline_mtr.h" 60 61 #define ETHDEV_FWVERS_LEN 32 62 63 #ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */ 64 #define CLOCK_TYPE_ID CLOCK_MONOTONIC_RAW 65 #else 66 #define CLOCK_TYPE_ID CLOCK_MONOTONIC 67 #endif 68 69 #define NS_PER_SEC 1E9 70 71 static const struct { 72 enum tx_pkt_split split; 73 const char *name; 74 } tx_split_name[] = { 75 { 76 .split = TX_PKT_SPLIT_OFF, 77 .name = "off", 78 }, 79 { 80 .split = TX_PKT_SPLIT_ON, 81 .name = "on", 82 }, 83 { 84 .split = TX_PKT_SPLIT_RND, 85 .name = "rand", 86 }, 87 }; 88 89 const struct rss_type_info rss_type_table[] = { 90 /* Group types */ 91 { "all", RTE_ETH_RSS_ETH | RTE_ETH_RSS_VLAN | RTE_ETH_RSS_IP | RTE_ETH_RSS_TCP | 92 RTE_ETH_RSS_UDP | RTE_ETH_RSS_SCTP | RTE_ETH_RSS_L2_PAYLOAD | 93 RTE_ETH_RSS_L2TPV3 | RTE_ETH_RSS_ESP | RTE_ETH_RSS_AH | RTE_ETH_RSS_PFCP | 94 RTE_ETH_RSS_GTPU | RTE_ETH_RSS_ECPRI | RTE_ETH_RSS_MPLS | RTE_ETH_RSS_L2TPV2}, 95 { "none", 0 }, 96 { "ip", RTE_ETH_RSS_IP }, 97 { "udp", RTE_ETH_RSS_UDP }, 98 { "tcp", RTE_ETH_RSS_TCP }, 99 { "sctp", RTE_ETH_RSS_SCTP }, 100 { "tunnel", RTE_ETH_RSS_TUNNEL }, 101 { "vlan", RTE_ETH_RSS_VLAN }, 102 103 /* Individual type */ 104 { "ipv4", RTE_ETH_RSS_IPV4 }, 105 { "ipv4-frag", RTE_ETH_RSS_FRAG_IPV4 }, 106 { "ipv4-tcp", RTE_ETH_RSS_NONFRAG_IPV4_TCP }, 107 { "ipv4-udp", RTE_ETH_RSS_NONFRAG_IPV4_UDP }, 108 { "ipv4-sctp", RTE_ETH_RSS_NONFRAG_IPV4_SCTP }, 109 { "ipv4-other", RTE_ETH_RSS_NONFRAG_IPV4_OTHER }, 110 { "ipv6", RTE_ETH_RSS_IPV6 }, 111 { "ipv6-frag", RTE_ETH_RSS_FRAG_IPV6 }, 112 { "ipv6-tcp", RTE_ETH_RSS_NONFRAG_IPV6_TCP }, 113 { "ipv6-udp", RTE_ETH_RSS_NONFRAG_IPV6_UDP }, 114 { "ipv6-sctp", RTE_ETH_RSS_NONFRAG_IPV6_SCTP }, 115 { "ipv6-other", RTE_ETH_RSS_NONFRAG_IPV6_OTHER }, 116 { "l2-payload", RTE_ETH_RSS_L2_PAYLOAD }, 117 { "ipv6-ex", RTE_ETH_RSS_IPV6_EX }, 118 { "ipv6-tcp-ex", RTE_ETH_RSS_IPV6_TCP_EX }, 119 { "ipv6-udp-ex", RTE_ETH_RSS_IPV6_UDP_EX }, 120 { "port", RTE_ETH_RSS_PORT }, 121 { "vxlan", RTE_ETH_RSS_VXLAN }, 122 { "geneve", RTE_ETH_RSS_GENEVE }, 123 { "nvgre", RTE_ETH_RSS_NVGRE }, 124 { "gtpu", RTE_ETH_RSS_GTPU }, 125 { "eth", RTE_ETH_RSS_ETH }, 126 { "s-vlan", RTE_ETH_RSS_S_VLAN }, 127 { "c-vlan", RTE_ETH_RSS_C_VLAN }, 128 { "esp", RTE_ETH_RSS_ESP }, 129 { "ah", RTE_ETH_RSS_AH }, 130 { "l2tpv3", RTE_ETH_RSS_L2TPV3 }, 131 { "pfcp", RTE_ETH_RSS_PFCP }, 132 { "pppoe", RTE_ETH_RSS_PPPOE }, 133 { "ecpri", RTE_ETH_RSS_ECPRI }, 134 { "mpls", RTE_ETH_RSS_MPLS }, 135 { "ipv4-chksum", RTE_ETH_RSS_IPV4_CHKSUM }, 136 { "l4-chksum", RTE_ETH_RSS_L4_CHKSUM }, 137 { "l2tpv2", RTE_ETH_RSS_L2TPV2 }, 138 { "l3-pre96", RTE_ETH_RSS_L3_PRE96 }, 139 { "l3-pre64", RTE_ETH_RSS_L3_PRE64 }, 140 { "l3-pre56", RTE_ETH_RSS_L3_PRE56 }, 141 { "l3-pre48", RTE_ETH_RSS_L3_PRE48 }, 142 { "l3-pre40", RTE_ETH_RSS_L3_PRE40 }, 143 { "l3-pre32", RTE_ETH_RSS_L3_PRE32 }, 144 { "l2-dst-only", RTE_ETH_RSS_L2_DST_ONLY }, 145 { "l2-src-only", RTE_ETH_RSS_L2_SRC_ONLY }, 146 { "l4-dst-only", RTE_ETH_RSS_L4_DST_ONLY }, 147 { "l4-src-only", RTE_ETH_RSS_L4_SRC_ONLY }, 148 { "l3-dst-only", RTE_ETH_RSS_L3_DST_ONLY }, 149 { "l3-src-only", RTE_ETH_RSS_L3_SRC_ONLY }, 150 { NULL, 0}, 151 }; 152 153 static const struct { 154 enum rte_eth_fec_mode mode; 155 const char *name; 156 } fec_mode_name[] = { 157 { 158 .mode = RTE_ETH_FEC_NOFEC, 159 .name = "off", 160 }, 161 { 162 .mode = RTE_ETH_FEC_AUTO, 163 .name = "auto", 164 }, 165 { 166 .mode = RTE_ETH_FEC_BASER, 167 .name = "baser", 168 }, 169 { 170 .mode = RTE_ETH_FEC_RS, 171 .name = "rs", 172 }, 173 }; 174 175 static const struct { 176 char str[32]; 177 uint16_t ftype; 178 } flowtype_str_table[] = { 179 {"raw", RTE_ETH_FLOW_RAW}, 180 {"ipv4", RTE_ETH_FLOW_IPV4}, 181 {"ipv4-frag", RTE_ETH_FLOW_FRAG_IPV4}, 182 {"ipv4-tcp", RTE_ETH_FLOW_NONFRAG_IPV4_TCP}, 183 {"ipv4-udp", RTE_ETH_FLOW_NONFRAG_IPV4_UDP}, 184 {"ipv4-sctp", RTE_ETH_FLOW_NONFRAG_IPV4_SCTP}, 185 {"ipv4-other", RTE_ETH_FLOW_NONFRAG_IPV4_OTHER}, 186 {"ipv6", RTE_ETH_FLOW_IPV6}, 187 {"ipv6-frag", RTE_ETH_FLOW_FRAG_IPV6}, 188 {"ipv6-tcp", RTE_ETH_FLOW_NONFRAG_IPV6_TCP}, 189 {"ipv6-udp", RTE_ETH_FLOW_NONFRAG_IPV6_UDP}, 190 {"ipv6-sctp", RTE_ETH_FLOW_NONFRAG_IPV6_SCTP}, 191 {"ipv6-other", RTE_ETH_FLOW_NONFRAG_IPV6_OTHER}, 192 {"l2_payload", RTE_ETH_FLOW_L2_PAYLOAD}, 193 {"ipv6-ex", RTE_ETH_FLOW_IPV6_EX}, 194 {"ipv6-tcp-ex", RTE_ETH_FLOW_IPV6_TCP_EX}, 195 {"ipv6-udp-ex", RTE_ETH_FLOW_IPV6_UDP_EX}, 196 {"port", RTE_ETH_FLOW_PORT}, 197 {"vxlan", RTE_ETH_FLOW_VXLAN}, 198 {"geneve", RTE_ETH_FLOW_GENEVE}, 199 {"nvgre", RTE_ETH_FLOW_NVGRE}, 200 {"vxlan-gpe", RTE_ETH_FLOW_VXLAN_GPE}, 201 {"gtpu", RTE_ETH_FLOW_GTPU}, 202 }; 203 204 static void 205 print_ethaddr(const char *name, struct rte_ether_addr *eth_addr) 206 { 207 char buf[RTE_ETHER_ADDR_FMT_SIZE]; 208 rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, eth_addr); 209 printf("%s%s", name, buf); 210 } 211 212 static void 213 nic_xstats_display_periodic(portid_t port_id) 214 { 215 struct xstat_display_info *xstats_info; 216 uint64_t *prev_values, *curr_values; 217 uint64_t diff_value, value_rate; 218 struct timespec cur_time; 219 uint64_t *ids_supp; 220 size_t ids_supp_sz; 221 uint64_t diff_ns; 222 unsigned int i; 223 int rc; 224 225 xstats_info = &ports[port_id].xstats_info; 226 227 ids_supp_sz = xstats_info->ids_supp_sz; 228 if (ids_supp_sz == 0) 229 return; 230 231 printf("\n"); 232 233 ids_supp = xstats_info->ids_supp; 234 prev_values = xstats_info->prev_values; 235 curr_values = xstats_info->curr_values; 236 237 rc = rte_eth_xstats_get_by_id(port_id, ids_supp, curr_values, 238 ids_supp_sz); 239 if (rc != (int)ids_supp_sz) { 240 fprintf(stderr, 241 "Failed to get values of %zu xstats for port %u - return code %d\n", 242 ids_supp_sz, port_id, rc); 243 return; 244 } 245 246 diff_ns = 0; 247 if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) { 248 uint64_t ns; 249 250 ns = cur_time.tv_sec * NS_PER_SEC; 251 ns += cur_time.tv_nsec; 252 253 if (xstats_info->prev_ns != 0) 254 diff_ns = ns - xstats_info->prev_ns; 255 xstats_info->prev_ns = ns; 256 } 257 258 printf("%-31s%-17s%s\n", " ", "Value", "Rate (since last show)"); 259 for (i = 0; i < ids_supp_sz; i++) { 260 diff_value = (curr_values[i] > prev_values[i]) ? 261 (curr_values[i] - prev_values[i]) : 0; 262 prev_values[i] = curr_values[i]; 263 value_rate = diff_ns > 0 ? 264 (double)diff_value / diff_ns * NS_PER_SEC : 0; 265 266 printf(" %-25s%12"PRIu64" %15"PRIu64"\n", 267 xstats_display[i].name, curr_values[i], value_rate); 268 } 269 } 270 271 void 272 nic_stats_display(portid_t port_id) 273 { 274 static uint64_t prev_pkts_rx[RTE_MAX_ETHPORTS]; 275 static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS]; 276 static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS]; 277 static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS]; 278 static uint64_t prev_ns[RTE_MAX_ETHPORTS]; 279 struct timespec cur_time; 280 uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx, 281 diff_ns; 282 uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx; 283 struct rte_eth_stats stats; 284 static const char *nic_stats_border = "########################"; 285 int ret; 286 287 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 288 print_valid_ports(); 289 return; 290 } 291 ret = rte_eth_stats_get(port_id, &stats); 292 if (ret != 0) { 293 fprintf(stderr, 294 "%s: Error: failed to get stats (port %u): %d", 295 __func__, port_id, ret); 296 return; 297 } 298 printf("\n %s NIC statistics for port %-2d %s\n", 299 nic_stats_border, port_id, nic_stats_border); 300 301 printf(" RX-packets: %-10"PRIu64" RX-missed: %-10"PRIu64" RX-bytes: " 302 "%-"PRIu64"\n", stats.ipackets, stats.imissed, stats.ibytes); 303 printf(" RX-errors: %-"PRIu64"\n", stats.ierrors); 304 printf(" RX-nombuf: %-10"PRIu64"\n", stats.rx_nombuf); 305 printf(" TX-packets: %-10"PRIu64" TX-errors: %-10"PRIu64" TX-bytes: " 306 "%-"PRIu64"\n", stats.opackets, stats.oerrors, stats.obytes); 307 308 diff_ns = 0; 309 if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) { 310 uint64_t ns; 311 312 ns = cur_time.tv_sec * NS_PER_SEC; 313 ns += cur_time.tv_nsec; 314 315 if (prev_ns[port_id] != 0) 316 diff_ns = ns - prev_ns[port_id]; 317 prev_ns[port_id] = ns; 318 } 319 320 diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ? 321 (stats.ipackets - prev_pkts_rx[port_id]) : 0; 322 diff_pkts_tx = (stats.opackets > prev_pkts_tx[port_id]) ? 323 (stats.opackets - prev_pkts_tx[port_id]) : 0; 324 prev_pkts_rx[port_id] = stats.ipackets; 325 prev_pkts_tx[port_id] = stats.opackets; 326 mpps_rx = diff_ns > 0 ? 327 (double)diff_pkts_rx / diff_ns * NS_PER_SEC : 0; 328 mpps_tx = diff_ns > 0 ? 329 (double)diff_pkts_tx / diff_ns * NS_PER_SEC : 0; 330 331 diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ? 332 (stats.ibytes - prev_bytes_rx[port_id]) : 0; 333 diff_bytes_tx = (stats.obytes > prev_bytes_tx[port_id]) ? 334 (stats.obytes - prev_bytes_tx[port_id]) : 0; 335 prev_bytes_rx[port_id] = stats.ibytes; 336 prev_bytes_tx[port_id] = stats.obytes; 337 mbps_rx = diff_ns > 0 ? 338 (double)diff_bytes_rx / diff_ns * NS_PER_SEC : 0; 339 mbps_tx = diff_ns > 0 ? 340 (double)diff_bytes_tx / diff_ns * NS_PER_SEC : 0; 341 342 printf("\n Throughput (since last show)\n"); 343 printf(" Rx-pps: %12"PRIu64" Rx-bps: %12"PRIu64"\n Tx-pps: %12" 344 PRIu64" Tx-bps: %12"PRIu64"\n", mpps_rx, mbps_rx * 8, 345 mpps_tx, mbps_tx * 8); 346 347 if (xstats_display_num > 0) 348 nic_xstats_display_periodic(port_id); 349 350 printf(" %s############################%s\n", 351 nic_stats_border, nic_stats_border); 352 } 353 354 void 355 nic_stats_clear(portid_t port_id) 356 { 357 int ret; 358 359 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 360 print_valid_ports(); 361 return; 362 } 363 364 ret = rte_eth_stats_reset(port_id); 365 if (ret != 0) { 366 fprintf(stderr, 367 "%s: Error: failed to reset stats (port %u): %s", 368 __func__, port_id, strerror(-ret)); 369 return; 370 } 371 372 ret = rte_eth_stats_get(port_id, &ports[port_id].stats); 373 if (ret != 0) { 374 if (ret < 0) 375 ret = -ret; 376 fprintf(stderr, 377 "%s: Error: failed to get stats (port %u): %s", 378 __func__, port_id, strerror(ret)); 379 return; 380 } 381 printf("\n NIC statistics for port %d cleared\n", port_id); 382 } 383 384 void 385 nic_xstats_display(portid_t port_id) 386 { 387 struct rte_eth_xstat *xstats; 388 int cnt_xstats, idx_xstat; 389 struct rte_eth_xstat_name *xstats_names; 390 391 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 392 print_valid_ports(); 393 return; 394 } 395 printf("###### NIC extended statistics for port %-2d\n", port_id); 396 if (!rte_eth_dev_is_valid_port(port_id)) { 397 fprintf(stderr, "Error: Invalid port number %i\n", port_id); 398 return; 399 } 400 401 /* Get count */ 402 cnt_xstats = rte_eth_xstats_get_names(port_id, NULL, 0); 403 if (cnt_xstats < 0) { 404 fprintf(stderr, "Error: Cannot get count of xstats\n"); 405 return; 406 } 407 408 /* Get id-name lookup table */ 409 xstats_names = malloc(sizeof(struct rte_eth_xstat_name) * cnt_xstats); 410 if (xstats_names == NULL) { 411 fprintf(stderr, "Cannot allocate memory for xstats lookup\n"); 412 return; 413 } 414 if (cnt_xstats != rte_eth_xstats_get_names( 415 port_id, xstats_names, cnt_xstats)) { 416 fprintf(stderr, "Error: Cannot get xstats lookup\n"); 417 free(xstats_names); 418 return; 419 } 420 421 /* Get stats themselves */ 422 xstats = malloc(sizeof(struct rte_eth_xstat) * cnt_xstats); 423 if (xstats == NULL) { 424 fprintf(stderr, "Cannot allocate memory for xstats\n"); 425 free(xstats_names); 426 return; 427 } 428 if (cnt_xstats != rte_eth_xstats_get(port_id, xstats, cnt_xstats)) { 429 fprintf(stderr, "Error: Unable to get xstats\n"); 430 free(xstats_names); 431 free(xstats); 432 return; 433 } 434 435 /* Display xstats */ 436 for (idx_xstat = 0; idx_xstat < cnt_xstats; idx_xstat++) { 437 if (xstats_hide_zero && !xstats[idx_xstat].value) 438 continue; 439 printf("%s: %"PRIu64"\n", 440 xstats_names[idx_xstat].name, 441 xstats[idx_xstat].value); 442 } 443 free(xstats_names); 444 free(xstats); 445 } 446 447 void 448 nic_xstats_clear(portid_t port_id) 449 { 450 int ret; 451 452 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 453 print_valid_ports(); 454 return; 455 } 456 457 ret = rte_eth_xstats_reset(port_id); 458 if (ret != 0) { 459 fprintf(stderr, 460 "%s: Error: failed to reset xstats (port %u): %s\n", 461 __func__, port_id, strerror(-ret)); 462 return; 463 } 464 465 ret = rte_eth_stats_get(port_id, &ports[port_id].stats); 466 if (ret != 0) { 467 if (ret < 0) 468 ret = -ret; 469 fprintf(stderr, "%s: Error: failed to get stats (port %u): %s", 470 __func__, port_id, strerror(ret)); 471 return; 472 } 473 } 474 475 static const char * 476 get_queue_state_name(uint8_t queue_state) 477 { 478 if (queue_state == RTE_ETH_QUEUE_STATE_STOPPED) 479 return "stopped"; 480 else if (queue_state == RTE_ETH_QUEUE_STATE_STARTED) 481 return "started"; 482 else if (queue_state == RTE_ETH_QUEUE_STATE_HAIRPIN) 483 return "hairpin"; 484 else 485 return "unknown"; 486 } 487 488 void 489 rx_queue_infos_display(portid_t port_id, uint16_t queue_id) 490 { 491 struct rte_eth_burst_mode mode; 492 struct rte_eth_rxq_info qinfo; 493 int32_t rc; 494 static const char *info_border = "*********************"; 495 496 rc = rte_eth_rx_queue_info_get(port_id, queue_id, &qinfo); 497 if (rc != 0) { 498 fprintf(stderr, 499 "Failed to retrieve information for port: %u, RX queue: %hu\nerror desc: %s(%d)\n", 500 port_id, queue_id, strerror(-rc), rc); 501 return; 502 } 503 504 printf("\n%s Infos for port %-2u, RX queue %-2u %s", 505 info_border, port_id, queue_id, info_border); 506 507 printf("\nMempool: %s", (qinfo.mp == NULL) ? "NULL" : qinfo.mp->name); 508 printf("\nRX prefetch threshold: %hhu", qinfo.conf.rx_thresh.pthresh); 509 printf("\nRX host threshold: %hhu", qinfo.conf.rx_thresh.hthresh); 510 printf("\nRX writeback threshold: %hhu", qinfo.conf.rx_thresh.wthresh); 511 printf("\nRX free threshold: %hu", qinfo.conf.rx_free_thresh); 512 printf("\nRX drop packets: %s", 513 (qinfo.conf.rx_drop_en != 0) ? "on" : "off"); 514 printf("\nRX deferred start: %s", 515 (qinfo.conf.rx_deferred_start != 0) ? "on" : "off"); 516 printf("\nRX scattered packets: %s", 517 (qinfo.scattered_rx != 0) ? "on" : "off"); 518 printf("\nRx queue state: %s", get_queue_state_name(qinfo.queue_state)); 519 if (qinfo.rx_buf_size != 0) 520 printf("\nRX buffer size: %hu", qinfo.rx_buf_size); 521 printf("\nNumber of RXDs: %hu", qinfo.nb_desc); 522 523 if (rte_eth_rx_burst_mode_get(port_id, queue_id, &mode) == 0) 524 printf("\nBurst mode: %s%s", 525 mode.info, 526 mode.flags & RTE_ETH_BURST_FLAG_PER_QUEUE ? 527 " (per queue)" : ""); 528 529 printf("\n"); 530 } 531 532 void 533 tx_queue_infos_display(portid_t port_id, uint16_t queue_id) 534 { 535 struct rte_eth_burst_mode mode; 536 struct rte_eth_txq_info qinfo; 537 int32_t rc; 538 static const char *info_border = "*********************"; 539 540 rc = rte_eth_tx_queue_info_get(port_id, queue_id, &qinfo); 541 if (rc != 0) { 542 fprintf(stderr, 543 "Failed to retrieve information for port: %u, TX queue: %hu\nerror desc: %s(%d)\n", 544 port_id, queue_id, strerror(-rc), rc); 545 return; 546 } 547 548 printf("\n%s Infos for port %-2u, TX queue %-2u %s", 549 info_border, port_id, queue_id, info_border); 550 551 printf("\nTX prefetch threshold: %hhu", qinfo.conf.tx_thresh.pthresh); 552 printf("\nTX host threshold: %hhu", qinfo.conf.tx_thresh.hthresh); 553 printf("\nTX writeback threshold: %hhu", qinfo.conf.tx_thresh.wthresh); 554 printf("\nTX RS threshold: %hu", qinfo.conf.tx_rs_thresh); 555 printf("\nTX free threshold: %hu", qinfo.conf.tx_free_thresh); 556 printf("\nTX deferred start: %s", 557 (qinfo.conf.tx_deferred_start != 0) ? "on" : "off"); 558 printf("\nNumber of TXDs: %hu", qinfo.nb_desc); 559 printf("\nTx queue state: %s", get_queue_state_name(qinfo.queue_state)); 560 561 if (rte_eth_tx_burst_mode_get(port_id, queue_id, &mode) == 0) 562 printf("\nBurst mode: %s%s", 563 mode.info, 564 mode.flags & RTE_ETH_BURST_FLAG_PER_QUEUE ? 565 " (per queue)" : ""); 566 567 printf("\n"); 568 } 569 570 static int bus_match_all(const struct rte_bus *bus, const void *data) 571 { 572 RTE_SET_USED(bus); 573 RTE_SET_USED(data); 574 return 0; 575 } 576 577 static void 578 device_infos_display_speeds(uint32_t speed_capa) 579 { 580 printf("\n\tDevice speed capability:"); 581 if (speed_capa == RTE_ETH_LINK_SPEED_AUTONEG) 582 printf(" Autonegotiate (all speeds)"); 583 if (speed_capa & RTE_ETH_LINK_SPEED_FIXED) 584 printf(" Disable autonegotiate (fixed speed) "); 585 if (speed_capa & RTE_ETH_LINK_SPEED_10M_HD) 586 printf(" 10 Mbps half-duplex "); 587 if (speed_capa & RTE_ETH_LINK_SPEED_10M) 588 printf(" 10 Mbps full-duplex "); 589 if (speed_capa & RTE_ETH_LINK_SPEED_100M_HD) 590 printf(" 100 Mbps half-duplex "); 591 if (speed_capa & RTE_ETH_LINK_SPEED_100M) 592 printf(" 100 Mbps full-duplex "); 593 if (speed_capa & RTE_ETH_LINK_SPEED_1G) 594 printf(" 1 Gbps "); 595 if (speed_capa & RTE_ETH_LINK_SPEED_2_5G) 596 printf(" 2.5 Gbps "); 597 if (speed_capa & RTE_ETH_LINK_SPEED_5G) 598 printf(" 5 Gbps "); 599 if (speed_capa & RTE_ETH_LINK_SPEED_10G) 600 printf(" 10 Gbps "); 601 if (speed_capa & RTE_ETH_LINK_SPEED_20G) 602 printf(" 20 Gbps "); 603 if (speed_capa & RTE_ETH_LINK_SPEED_25G) 604 printf(" 25 Gbps "); 605 if (speed_capa & RTE_ETH_LINK_SPEED_40G) 606 printf(" 40 Gbps "); 607 if (speed_capa & RTE_ETH_LINK_SPEED_50G) 608 printf(" 50 Gbps "); 609 if (speed_capa & RTE_ETH_LINK_SPEED_56G) 610 printf(" 56 Gbps "); 611 if (speed_capa & RTE_ETH_LINK_SPEED_100G) 612 printf(" 100 Gbps "); 613 if (speed_capa & RTE_ETH_LINK_SPEED_200G) 614 printf(" 200 Gbps "); 615 if (speed_capa & RTE_ETH_LINK_SPEED_400G) 616 printf(" 400 Gbps "); 617 } 618 619 void 620 device_infos_display(const char *identifier) 621 { 622 static const char *info_border = "*********************"; 623 struct rte_bus *start = NULL, *next; 624 struct rte_dev_iterator dev_iter; 625 char name[RTE_ETH_NAME_MAX_LEN]; 626 struct rte_ether_addr mac_addr; 627 struct rte_device *dev; 628 struct rte_devargs da; 629 portid_t port_id; 630 struct rte_eth_dev_info dev_info; 631 char devstr[128]; 632 633 memset(&da, 0, sizeof(da)); 634 if (!identifier) 635 goto skip_parse; 636 637 if (rte_devargs_parsef(&da, "%s", identifier)) { 638 fprintf(stderr, "cannot parse identifier\n"); 639 return; 640 } 641 642 skip_parse: 643 while ((next = rte_bus_find(start, bus_match_all, NULL)) != NULL) { 644 645 start = next; 646 if (identifier && da.bus != next) 647 continue; 648 649 snprintf(devstr, sizeof(devstr), "bus=%s", rte_bus_name(next)); 650 RTE_DEV_FOREACH(dev, devstr, &dev_iter) { 651 652 if (rte_dev_driver(dev) == NULL) 653 continue; 654 /* Check for matching device if identifier is present */ 655 if (identifier && 656 strncmp(da.name, rte_dev_name(dev), strlen(rte_dev_name(dev)))) 657 continue; 658 printf("\n%s Infos for device %s %s\n", 659 info_border, rte_dev_name(dev), info_border); 660 printf("Bus name: %s", rte_bus_name(rte_dev_bus(dev))); 661 printf("\nBus information: %s", 662 rte_dev_bus_info(dev) ? rte_dev_bus_info(dev) : ""); 663 printf("\nDriver name: %s", rte_driver_name(rte_dev_driver(dev))); 664 printf("\nDevargs: %s", 665 rte_dev_devargs(dev) ? rte_dev_devargs(dev)->args : ""); 666 printf("\nConnect to socket: %d", rte_dev_numa_node(dev)); 667 printf("\n"); 668 669 /* List ports with matching device name */ 670 RTE_ETH_FOREACH_DEV_OF(port_id, dev) { 671 printf("\n\tPort id: %-2d", port_id); 672 if (eth_macaddr_get_print_err(port_id, 673 &mac_addr) == 0) 674 print_ethaddr("\n\tMAC address: ", 675 &mac_addr); 676 rte_eth_dev_get_name_by_port(port_id, name); 677 printf("\n\tDevice name: %s", name); 678 if (rte_eth_dev_info_get(port_id, &dev_info) == 0) 679 device_infos_display_speeds(dev_info.speed_capa); 680 printf("\n"); 681 } 682 } 683 }; 684 rte_devargs_reset(&da); 685 } 686 687 static void 688 print_dev_capabilities(uint64_t capabilities) 689 { 690 uint64_t single_capa; 691 int begin; 692 int end; 693 int bit; 694 695 if (capabilities == 0) 696 return; 697 698 begin = __builtin_ctzll(capabilities); 699 end = sizeof(capabilities) * CHAR_BIT - __builtin_clzll(capabilities); 700 701 single_capa = 1ULL << begin; 702 for (bit = begin; bit < end; bit++) { 703 if (capabilities & single_capa) 704 printf(" %s", 705 rte_eth_dev_capability_name(single_capa)); 706 single_capa <<= 1; 707 } 708 } 709 710 uint64_t 711 str_to_rsstypes(const char *str) 712 { 713 uint16_t i; 714 715 for (i = 0; rss_type_table[i].str != NULL; i++) { 716 if (strcmp(rss_type_table[i].str, str) == 0) 717 return rss_type_table[i].rss_type; 718 } 719 720 return 0; 721 } 722 723 const char * 724 rsstypes_to_str(uint64_t rss_type) 725 { 726 uint16_t i; 727 728 for (i = 0; rss_type_table[i].str != NULL; i++) { 729 if (rss_type_table[i].rss_type == rss_type) 730 return rss_type_table[i].str; 731 } 732 733 return NULL; 734 } 735 736 static void 737 rss_offload_types_display(uint64_t offload_types, uint16_t char_num_per_line) 738 { 739 uint16_t user_defined_str_len; 740 uint16_t total_len = 0; 741 uint16_t str_len = 0; 742 uint64_t rss_offload; 743 uint16_t i; 744 745 for (i = 0; i < sizeof(offload_types) * CHAR_BIT; i++) { 746 rss_offload = RTE_BIT64(i); 747 if ((offload_types & rss_offload) != 0) { 748 const char *p = rsstypes_to_str(rss_offload); 749 750 user_defined_str_len = 751 strlen("user-defined-") + (i / 10 + 1); 752 str_len = p ? strlen(p) : user_defined_str_len; 753 str_len += 2; /* add two spaces */ 754 if (total_len + str_len >= char_num_per_line) { 755 total_len = 0; 756 printf("\n"); 757 } 758 759 if (p) 760 printf(" %s", p); 761 else 762 printf(" user-defined-%u", i); 763 total_len += str_len; 764 } 765 } 766 printf("\n"); 767 } 768 769 void 770 port_infos_display(portid_t port_id) 771 { 772 struct rte_port *port; 773 struct rte_ether_addr mac_addr; 774 struct rte_eth_link link; 775 struct rte_eth_dev_info dev_info; 776 int vlan_offload; 777 struct rte_mempool * mp; 778 static const char *info_border = "*********************"; 779 uint16_t mtu; 780 char name[RTE_ETH_NAME_MAX_LEN]; 781 int ret; 782 char fw_version[ETHDEV_FWVERS_LEN]; 783 784 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 785 print_valid_ports(); 786 return; 787 } 788 port = &ports[port_id]; 789 ret = eth_link_get_nowait_print_err(port_id, &link); 790 if (ret < 0) 791 return; 792 793 ret = eth_dev_info_get_print_err(port_id, &dev_info); 794 if (ret != 0) 795 return; 796 797 printf("\n%s Infos for port %-2d %s\n", 798 info_border, port_id, info_border); 799 if (eth_macaddr_get_print_err(port_id, &mac_addr) == 0) 800 print_ethaddr("MAC address: ", &mac_addr); 801 rte_eth_dev_get_name_by_port(port_id, name); 802 printf("\nDevice name: %s", name); 803 printf("\nDriver name: %s", dev_info.driver_name); 804 805 if (rte_eth_dev_fw_version_get(port_id, fw_version, 806 ETHDEV_FWVERS_LEN) == 0) 807 printf("\nFirmware-version: %s", fw_version); 808 else 809 printf("\nFirmware-version: %s", "not available"); 810 811 if (rte_dev_devargs(dev_info.device) && rte_dev_devargs(dev_info.device)->args) 812 printf("\nDevargs: %s", rte_dev_devargs(dev_info.device)->args); 813 printf("\nConnect to socket: %u", port->socket_id); 814 815 if (port_numa[port_id] != NUMA_NO_CONFIG) { 816 mp = mbuf_pool_find(port_numa[port_id], 0); 817 if (mp) 818 printf("\nmemory allocation on the socket: %d", 819 port_numa[port_id]); 820 } else 821 printf("\nmemory allocation on the socket: %u",port->socket_id); 822 823 printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down")); 824 printf("Link speed: %s\n", rte_eth_link_speed_to_str(link.link_speed)); 825 printf("Link duplex: %s\n", (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ? 826 ("full-duplex") : ("half-duplex")); 827 printf("Autoneg status: %s\n", (link.link_autoneg == RTE_ETH_LINK_AUTONEG) ? 828 ("On") : ("Off")); 829 830 if (!rte_eth_dev_get_mtu(port_id, &mtu)) 831 printf("MTU: %u\n", mtu); 832 833 printf("Promiscuous mode: %s\n", 834 rte_eth_promiscuous_get(port_id) ? "enabled" : "disabled"); 835 printf("Allmulticast mode: %s\n", 836 rte_eth_allmulticast_get(port_id) ? "enabled" : "disabled"); 837 printf("Maximum number of MAC addresses: %u\n", 838 (unsigned int)(port->dev_info.max_mac_addrs)); 839 printf("Maximum number of MAC addresses of hash filtering: %u\n", 840 (unsigned int)(port->dev_info.max_hash_mac_addrs)); 841 842 vlan_offload = rte_eth_dev_get_vlan_offload(port_id); 843 if (vlan_offload >= 0){ 844 printf("VLAN offload: \n"); 845 if (vlan_offload & RTE_ETH_VLAN_STRIP_OFFLOAD) 846 printf(" strip on, "); 847 else 848 printf(" strip off, "); 849 850 if (vlan_offload & RTE_ETH_VLAN_FILTER_OFFLOAD) 851 printf("filter on, "); 852 else 853 printf("filter off, "); 854 855 if (vlan_offload & RTE_ETH_VLAN_EXTEND_OFFLOAD) 856 printf("extend on, "); 857 else 858 printf("extend off, "); 859 860 if (vlan_offload & RTE_ETH_QINQ_STRIP_OFFLOAD) 861 printf("qinq strip on\n"); 862 else 863 printf("qinq strip off\n"); 864 } 865 866 if (dev_info.hash_key_size > 0) 867 printf("Hash key size in bytes: %u\n", dev_info.hash_key_size); 868 if (dev_info.reta_size > 0) 869 printf("Redirection table size: %u\n", dev_info.reta_size); 870 if (!dev_info.flow_type_rss_offloads) 871 printf("No RSS offload flow type is supported.\n"); 872 else { 873 printf("Supported RSS offload flow types:\n"); 874 rss_offload_types_display(dev_info.flow_type_rss_offloads, 875 TESTPMD_RSS_TYPES_CHAR_NUM_PER_LINE); 876 } 877 878 printf("Minimum size of RX buffer: %u\n", dev_info.min_rx_bufsize); 879 printf("Maximum configurable length of RX packet: %u\n", 880 dev_info.max_rx_pktlen); 881 printf("Maximum configurable size of LRO aggregated packet: %u\n", 882 dev_info.max_lro_pkt_size); 883 if (dev_info.max_vfs) 884 printf("Maximum number of VFs: %u\n", dev_info.max_vfs); 885 if (dev_info.max_vmdq_pools) 886 printf("Maximum number of VMDq pools: %u\n", 887 dev_info.max_vmdq_pools); 888 889 printf("Current number of RX queues: %u\n", dev_info.nb_rx_queues); 890 printf("Max possible RX queues: %u\n", dev_info.max_rx_queues); 891 printf("Max possible number of RXDs per queue: %hu\n", 892 dev_info.rx_desc_lim.nb_max); 893 printf("Min possible number of RXDs per queue: %hu\n", 894 dev_info.rx_desc_lim.nb_min); 895 printf("RXDs number alignment: %hu\n", dev_info.rx_desc_lim.nb_align); 896 897 printf("Current number of TX queues: %u\n", dev_info.nb_tx_queues); 898 printf("Max possible TX queues: %u\n", dev_info.max_tx_queues); 899 printf("Max possible number of TXDs per queue: %hu\n", 900 dev_info.tx_desc_lim.nb_max); 901 printf("Min possible number of TXDs per queue: %hu\n", 902 dev_info.tx_desc_lim.nb_min); 903 printf("TXDs number alignment: %hu\n", dev_info.tx_desc_lim.nb_align); 904 printf("Max segment number per packet: %hu\n", 905 dev_info.tx_desc_lim.nb_seg_max); 906 printf("Max segment number per MTU/TSO: %hu\n", 907 dev_info.tx_desc_lim.nb_mtu_seg_max); 908 909 printf("Device capabilities: 0x%"PRIx64"(", dev_info.dev_capa); 910 print_dev_capabilities(dev_info.dev_capa); 911 printf(" )\n"); 912 /* Show switch info only if valid switch domain and port id is set */ 913 if (dev_info.switch_info.domain_id != 914 RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID) { 915 if (dev_info.switch_info.name) 916 printf("Switch name: %s\n", dev_info.switch_info.name); 917 918 printf("Switch domain Id: %u\n", 919 dev_info.switch_info.domain_id); 920 printf("Switch Port Id: %u\n", 921 dev_info.switch_info.port_id); 922 if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) != 0) 923 printf("Switch Rx domain: %u\n", 924 dev_info.switch_info.rx_domain); 925 } 926 printf("Device error handling mode: "); 927 switch (dev_info.err_handle_mode) { 928 case RTE_ETH_ERROR_HANDLE_MODE_NONE: 929 printf("none\n"); 930 break; 931 case RTE_ETH_ERROR_HANDLE_MODE_PASSIVE: 932 printf("passive\n"); 933 break; 934 case RTE_ETH_ERROR_HANDLE_MODE_PROACTIVE: 935 printf("proactive\n"); 936 break; 937 default: 938 printf("unknown\n"); 939 break; 940 } 941 printf("Device private info:\n"); 942 ret = rte_eth_dev_priv_dump(port_id, stdout); 943 if (ret == -ENOTSUP) 944 printf(" none\n"); 945 else if (ret < 0) 946 fprintf(stderr, " Failed to dump private info with error (%d): %s\n", 947 ret, strerror(-ret)); 948 } 949 950 void 951 port_summary_header_display(void) 952 { 953 uint16_t port_number; 954 955 port_number = rte_eth_dev_count_avail(); 956 printf("Number of available ports: %i\n", port_number); 957 printf("%-4s %-17s %-12s %-14s %-8s %s\n", "Port", "MAC Address", "Name", 958 "Driver", "Status", "Link"); 959 } 960 961 void 962 port_summary_display(portid_t port_id) 963 { 964 struct rte_ether_addr mac_addr; 965 struct rte_eth_link link; 966 struct rte_eth_dev_info dev_info; 967 char name[RTE_ETH_NAME_MAX_LEN]; 968 int ret; 969 970 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 971 print_valid_ports(); 972 return; 973 } 974 975 ret = eth_link_get_nowait_print_err(port_id, &link); 976 if (ret < 0) 977 return; 978 979 ret = eth_dev_info_get_print_err(port_id, &dev_info); 980 if (ret != 0) 981 return; 982 983 rte_eth_dev_get_name_by_port(port_id, name); 984 ret = eth_macaddr_get_print_err(port_id, &mac_addr); 985 if (ret != 0) 986 return; 987 988 printf("%-4d " RTE_ETHER_ADDR_PRT_FMT " %-12s %-14s %-8s %s\n", 989 port_id, RTE_ETHER_ADDR_BYTES(&mac_addr), name, 990 dev_info.driver_name, (link.link_status) ? ("up") : ("down"), 991 rte_eth_link_speed_to_str(link.link_speed)); 992 } 993 994 void 995 port_eeprom_display(portid_t port_id) 996 { 997 struct rte_dev_eeprom_info einfo; 998 int ret; 999 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 1000 print_valid_ports(); 1001 return; 1002 } 1003 1004 int len_eeprom = rte_eth_dev_get_eeprom_length(port_id); 1005 if (len_eeprom < 0) { 1006 switch (len_eeprom) { 1007 case -ENODEV: 1008 fprintf(stderr, "port index %d invalid\n", port_id); 1009 break; 1010 case -ENOTSUP: 1011 fprintf(stderr, "operation not supported by device\n"); 1012 break; 1013 case -EIO: 1014 fprintf(stderr, "device is removed\n"); 1015 break; 1016 default: 1017 fprintf(stderr, "Unable to get EEPROM: %d\n", 1018 len_eeprom); 1019 break; 1020 } 1021 return; 1022 } 1023 1024 einfo.offset = 0; 1025 einfo.length = len_eeprom; 1026 einfo.data = calloc(1, len_eeprom); 1027 if (!einfo.data) { 1028 fprintf(stderr, 1029 "Allocation of port %u eeprom data failed\n", 1030 port_id); 1031 return; 1032 } 1033 1034 ret = rte_eth_dev_get_eeprom(port_id, &einfo); 1035 if (ret != 0) { 1036 switch (ret) { 1037 case -ENODEV: 1038 fprintf(stderr, "port index %d invalid\n", port_id); 1039 break; 1040 case -ENOTSUP: 1041 fprintf(stderr, "operation not supported by device\n"); 1042 break; 1043 case -EIO: 1044 fprintf(stderr, "device is removed\n"); 1045 break; 1046 default: 1047 fprintf(stderr, "Unable to get EEPROM: %d\n", ret); 1048 break; 1049 } 1050 free(einfo.data); 1051 return; 1052 } 1053 rte_hexdump(stdout, "hexdump", einfo.data, einfo.length); 1054 printf("Finish -- Port: %d EEPROM length: %d bytes\n", port_id, len_eeprom); 1055 free(einfo.data); 1056 } 1057 1058 void 1059 port_module_eeprom_display(portid_t port_id) 1060 { 1061 struct rte_eth_dev_module_info minfo; 1062 struct rte_dev_eeprom_info einfo; 1063 int ret; 1064 1065 if (port_id_is_invalid(port_id, ENABLED_WARN)) { 1066 print_valid_ports(); 1067 return; 1068 } 1069 1070 1071 ret = rte_eth_dev_get_module_info(port_id, &minfo); 1072 if (ret != 0) { 1073 switch (ret) { 1074 case -ENODEV: 1075 fprintf(stderr, "port index %d invalid\n", port_id); 1076 break; 1077 case -ENOTSUP: 1078 fprintf(stderr, "operation not supported by device\n"); 1079 break; 1080 case -EIO: 1081 fprintf(stderr, "device is removed\n"); 1082 break; 1083 default: 1084 fprintf(stderr, "Unable to get module EEPROM: %d\n", 1085 ret); 1086 break; 1087 } 1088 return; 1089 } 1090 1091 einfo.offset = 0; 1092 einfo.length = minfo.eeprom_len; 1093 einfo.data = calloc(1, minfo.eeprom_len); 1094 if (!einfo.data) { 1095 fprintf(stderr, 1096 "Allocation of port %u eeprom data failed\n", 1097 port_id); 1098 return; 1099 } 1100 1101 ret = rte_eth_dev_get_module_eeprom(port_id, &einfo); 1102 if (ret != 0) { 1103 switch (ret) { 1104 case -ENODEV: 1105 fprintf(stderr, "port index %d invalid\n", port_id); 1106 break; 1107 case -ENOTSUP: 1108 fprintf(stderr, "operation not supported by device\n"); 1109 break; 1110 case -EIO: 1111 fprintf(stderr, "device is removed\n"); 1112 break; 1113 default: 1114 fprintf(stderr, "Unable to get module EEPROM: %d\n", 1115 ret); 1116 break; 1117 } 1118 free(einfo.data); 1119 return; 1120 } 1121 1122 rte_hexdump(stdout, "hexdump", einfo.data, einfo.length); 1123 printf("Finish -- Port: %d MODULE EEPROM length: %d bytes\n", port_id, einfo.length); 1124 free(einfo.data); 1125 } 1126 1127 int 1128 port_id_is_invalid(portid_t port_id, enum print_warning warning) 1129 { 1130 uint16_t pid; 1131 1132 if (port_id == (portid_t)RTE_PORT_ALL) 1133 return 0; 1134 1135 RTE_ETH_FOREACH_DEV(pid) 1136 if (port_id == pid) 1137 return 0; 1138 1139 if (warning == ENABLED_WARN) 1140 fprintf(stderr, "Invalid port %d\n", port_id); 1141 1142 return 1; 1143 } 1144 1145 void print_valid_ports(void) 1146 { 1147 portid_t pid; 1148 1149 printf("The valid ports array is ["); 1150 RTE_ETH_FOREACH_DEV(pid) { 1151 printf(" %d", pid); 1152 } 1153 printf(" ]\n"); 1154 } 1155 1156 static int 1157 vlan_id_is_invalid(uint16_t vlan_id) 1158 { 1159 if (vlan_id < 4096) 1160 return 0; 1161 fprintf(stderr, "Invalid vlan_id %d (must be < 4096)\n", vlan_id); 1162 return 1; 1163 } 1164 1165 static uint32_t 1166 eth_dev_get_overhead_len(uint32_t max_rx_pktlen, uint16_t max_mtu) 1167 { 1168 uint32_t overhead_len; 1169 1170 if (max_mtu != UINT16_MAX && max_rx_pktlen > max_mtu) 1171 overhead_len = max_rx_pktlen - max_mtu; 1172 else 1173 overhead_len = RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN; 1174 1175 return overhead_len; 1176 } 1177 1178 static int 1179 eth_dev_validate_mtu(uint16_t port_id, uint16_t mtu) 1180 { 1181 struct rte_eth_dev_info dev_info; 1182 uint32_t overhead_len; 1183 uint32_t frame_size; 1184 int ret; 1185 1186 ret = rte_eth_dev_info_get(port_id, &dev_info); 1187 if (ret != 0) 1188 return ret; 1189 1190 if (mtu < dev_info.min_mtu) { 1191 fprintf(stderr, 1192 "MTU (%u) < device min MTU (%u) for port_id %u\n", 1193 mtu, dev_info.min_mtu, port_id); 1194 return -EINVAL; 1195 } 1196 if (mtu > dev_info.max_mtu) { 1197 fprintf(stderr, 1198 "MTU (%u) > device max MTU (%u) for port_id %u\n", 1199 mtu, dev_info.max_mtu, port_id); 1200 return -EINVAL; 1201 } 1202 1203 overhead_len = eth_dev_get_overhead_len(dev_info.max_rx_pktlen, 1204 dev_info.max_mtu); 1205 frame_size = mtu + overhead_len; 1206 if (frame_size > dev_info.max_rx_pktlen) { 1207 fprintf(stderr, 1208 "Frame size (%u) > device max frame size (%u) for port_id %u\n", 1209 frame_size, dev_info.max_rx_pktlen, port_id); 1210 return -EINVAL; 1211 } 1212 1213 return 0; 1214 } 1215 1216 void 1217 port_mtu_set(portid_t port_id, uint16_t mtu) 1218 { 1219 struct rte_port *port = &ports[port_id]; 1220 int diag; 1221 1222 if (port_id_is_invalid(port_id, ENABLED_WARN)) 1223 return; 1224 1225 diag = eth_dev_validate_mtu(port_id, mtu); 1226 if (diag != 0) 1227 return; 1228 1229 if (port->need_reconfig == 0) { 1230 diag = rte_eth_dev_set_mtu(port_id, mtu); 1231 if (diag != 0) { 1232 fprintf(stderr, "Set MTU failed. diag=%d\n", diag); 1233 return; 1234 } 1235 } 1236 1237 port->dev_conf.rxmode.mtu = mtu; 1238 } 1239 1240 /* Generic flow management functions. */ 1241 1242 static struct port_flow_tunnel * 1243 port_flow_locate_tunnel_id(struct rte_port *port, uint32_t port_tunnel_id) 1244 { 1245 struct port_flow_tunnel *flow_tunnel; 1246 1247 LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { 1248 if (flow_tunnel->id == port_tunnel_id) 1249 goto out; 1250 } 1251 flow_tunnel = NULL; 1252 1253 out: 1254 return flow_tunnel; 1255 } 1256 1257 const char * 1258 port_flow_tunnel_type(struct rte_flow_tunnel *tunnel) 1259 { 1260 const char *type; 1261 switch (tunnel->type) { 1262 default: 1263 type = "unknown"; 1264 break; 1265 case RTE_FLOW_ITEM_TYPE_VXLAN: 1266 type = "vxlan"; 1267 break; 1268 case RTE_FLOW_ITEM_TYPE_GRE: 1269 type = "gre"; 1270 break; 1271 case RTE_FLOW_ITEM_TYPE_NVGRE: 1272 type = "nvgre"; 1273 break; 1274 case RTE_FLOW_ITEM_TYPE_GENEVE: 1275 type = "geneve"; 1276 break; 1277 } 1278 1279 return type; 1280 } 1281 1282 struct port_flow_tunnel * 1283 port_flow_locate_tunnel(uint16_t port_id, struct rte_flow_tunnel *tun) 1284 { 1285 struct rte_port *port = &ports[port_id]; 1286 struct port_flow_tunnel *flow_tunnel; 1287 1288 LIST_FOREACH(flow_tunnel, &port->flow_tunnel_list, chain) { 1289 if (!memcmp(&flow_tunnel->tunnel, tun, sizeof(*tun))) 1290 goto out; 1291 } 1292 flow_tunnel = NULL; 1293 1294 out: 1295 return flow_tunnel; 1296 } 1297 1298 void port_flow_tunnel_list(portid_t port_id) 1299 { 1300 struct rte_port *port = &ports[port_id]; 1301 struct port_flow_tunnel *flt; 1302 1303 LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { 1304 printf("port %u tunnel #%u type=%s", 1305 port_id, flt->id, port_flow_tunnel_type(&flt->tunnel)); 1306 if (flt->tunnel.tun_id) 1307 printf(" id=%" PRIu64, flt->tunnel.tun_id); 1308 printf("\n"); 1309 } 1310 } 1311 1312 void port_flow_tunnel_destroy(portid_t port_id, uint32_t tunnel_id) 1313 { 1314 struct rte_port *port = &ports[port_id]; 1315 struct port_flow_tunnel *flt; 1316 1317 LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { 1318 if (flt->id == tunnel_id) 1319 break; 1320 } 1321 if (flt) { 1322 LIST_REMOVE(flt, chain); 1323 free(flt); 1324 printf("port %u: flow tunnel #%u destroyed\n", 1325 port_id, tunnel_id); 1326 } 1327 } 1328 1329 void port_flow_tunnel_create(portid_t port_id, const struct tunnel_ops *ops) 1330 { 1331 struct rte_port *port = &ports[port_id]; 1332 enum rte_flow_item_type type; 1333 struct port_flow_tunnel *flt; 1334 1335 if (!strcmp(ops->type, "vxlan")) 1336 type = RTE_FLOW_ITEM_TYPE_VXLAN; 1337 else if (!strcmp(ops->type, "gre")) 1338 type = RTE_FLOW_ITEM_TYPE_GRE; 1339 else if (!strcmp(ops->type, "nvgre")) 1340 type = RTE_FLOW_ITEM_TYPE_NVGRE; 1341 else if (!strcmp(ops->type, "geneve")) 1342 type = RTE_FLOW_ITEM_TYPE_GENEVE; 1343 else { 1344 fprintf(stderr, "cannot offload \"%s\" tunnel type\n", 1345 ops->type); 1346 return; 1347 } 1348 LIST_FOREACH(flt, &port->flow_tunnel_list, chain) { 1349 if (flt->tunnel.type == type) 1350 break; 1351 } 1352 if (!flt) { 1353 flt = calloc(1, sizeof(*flt)); 1354 if (!flt) { 1355 fprintf(stderr, "failed to allocate port flt object\n"); 1356 return; 1357 } 1358 flt->tunnel.type = type; 1359 flt->id = LIST_EMPTY(&port->flow_tunnel_list) ? 1 : 1360 LIST_FIRST(&port->flow_tunnel_list)->id + 1; 1361 LIST_INSERT_HEAD(&port->flow_tunnel_list, flt, chain); 1362 } 1363 printf("port %d: flow tunnel #%u type %s\n", 1364 port_id, flt->id, ops->type); 1365 } 1366 1367 /** Generate a port_flow entry from attributes/pattern/actions. */ 1368 static struct port_flow * 1369 port_flow_new(const struct rte_flow_attr *attr, 1370 const struct rte_flow_item *pattern, 1371 const struct rte_flow_action *actions, 1372 struct rte_flow_error *error) 1373 { 1374 const struct rte_flow_conv_rule rule = { 1375 .attr_ro = attr, 1376 .pattern_ro = pattern, 1377 .actions_ro = actions, 1378 }; 1379 struct port_flow *pf; 1380 int ret; 1381 1382 ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, NULL, 0, &rule, error); 1383 if (ret < 0) 1384 return NULL; 1385 pf = calloc(1, offsetof(struct port_flow, rule) + ret); 1386 if (!pf) { 1387 rte_flow_error_set 1388 (error, errno, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL, 1389 "calloc() failed"); 1390 return NULL; 1391 } 1392 if (rte_flow_conv(RTE_FLOW_CONV_OP_RULE, &pf->rule, ret, &rule, 1393 error) >= 0) 1394 return pf; 1395 free(pf); 1396 return NULL; 1397 } 1398 1399 /** Print a message out of a flow error. */ 1400 static int 1401 port_flow_complain(struct rte_flow_error *error) 1402 { 1403 static const char *const errstrlist[] = { 1404 [RTE_FLOW_ERROR_TYPE_NONE] = "no error", 1405 [RTE_FLOW_ERROR_TYPE_UNSPECIFIED] = "cause unspecified", 1406 [RTE_FLOW_ERROR_TYPE_HANDLE] = "flow rule (handle)", 1407 [RTE_FLOW_ERROR_TYPE_ATTR_GROUP] = "group field", 1408 [RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY] = "priority field", 1409 [RTE_FLOW_ERROR_TYPE_ATTR_INGRESS] = "ingress field", 1410 [RTE_FLOW_ERROR_TYPE_ATTR_EGRESS] = "egress field", 1411 [RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER] = "transfer field", 1412 [RTE_FLOW_ERROR_TYPE_ATTR] = "attributes structure", 1413 [RTE_FLOW_ERROR_TYPE_ITEM_NUM] = "pattern length", 1414 [RTE_FLOW_ERROR_TYPE_ITEM_SPEC] = "item specification", 1415 [RTE_FLOW_ERROR_TYPE_ITEM_LAST] = "item specification range", 1416 [RTE_FLOW_ERROR_TYPE_ITEM_MASK] = "item specification mask", 1417 [RTE_FLOW_ERROR_TYPE_ITEM] = "specific pattern item", 1418 [RTE_FLOW_ERROR_TYPE_ACTION_NUM] = "number of actions", 1419 [RTE_FLOW_ERROR_TYPE_ACTION_CONF] = "action configuration", 1420 [RTE_FLOW_ERROR_TYPE_ACTION] = "specific action", 1421 }; 1422 const char *errstr; 1423 char buf[32]; 1424 int err = rte_errno; 1425 1426 if ((unsigned int)error->type >= RTE_DIM(errstrlist) || 1427 !errstrlist[error->type]) 1428 errstr = "unknown type"; 1429 else 1430 errstr = errstrlist[error->type]; 1431 fprintf(stderr, "%s(): Caught PMD error type %d (%s): %s%s: %s\n", 1432 __func__, error->type, errstr, 1433 error->cause ? (snprintf(buf, sizeof(buf), "cause: %p, ", 1434 error->cause), buf) : "", 1435 error->message ? error->message : "(no stated reason)", 1436 rte_strerror(err)); 1437 1438 switch (error->type) { 1439 case RTE_FLOW_ERROR_TYPE_ATTR_TRANSFER: 1440 fprintf(stderr, "The status suggests the use of \"transfer\" " 1441 "as the possible cause of the failure. Make " 1442 "sure that the flow in question and its " 1443 "indirect components (if any) are managed " 1444 "via \"transfer\" proxy port. Use command " 1445 "\"show port (port_id) flow transfer proxy\" " 1446 "to figure out the proxy port ID\n"); 1447 break; 1448 default: 1449 break; 1450 } 1451 1452 return -err; 1453 } 1454 1455 static void 1456 rss_types_display(uint64_t rss_types, uint16_t char_num_per_line) 1457 { 1458 uint16_t total_len = 0; 1459 uint16_t str_len; 1460 uint16_t i; 1461 1462 if (rss_types == 0) 1463 return; 1464 1465 for (i = 0; rss_type_table[i].str; i++) { 1466 if (rss_type_table[i].rss_type == 0) 1467 continue; 1468 1469 if ((rss_types & rss_type_table[i].rss_type) == 1470 rss_type_table[i].rss_type) { 1471 /* Contain two spaces */ 1472 str_len = strlen(rss_type_table[i].str) + 2; 1473 if (total_len + str_len > char_num_per_line) { 1474 printf("\n"); 1475 total_len = 0; 1476 } 1477 printf(" %s", rss_type_table[i].str); 1478 total_len += str_len; 1479 } 1480 } 1481 printf("\n"); 1482 } 1483 1484 static void 1485 rss_config_display(struct rte_flow_action_rss *rss_conf) 1486 { 1487 uint8_t i; 1488 1489 if (rss_conf == NULL) { 1490 fprintf(stderr, "Invalid rule\n"); 1491 return; 1492 } 1493 1494 printf("RSS:\n" 1495 " queues:"); 1496 if (rss_conf->queue_num == 0) 1497 printf(" none"); 1498 for (i = 0; i < rss_conf->queue_num; i++) 1499 printf(" %d", rss_conf->queue[i]); 1500 printf("\n"); 1501 1502 printf(" function: "); 1503 switch (rss_conf->func) { 1504 case RTE_ETH_HASH_FUNCTION_DEFAULT: 1505 printf("default\n"); 1506 break; 1507 case RTE_ETH_HASH_FUNCTION_TOEPLITZ: 1508 printf("toeplitz\n"); 1509 break; 1510 case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR: 1511 printf("simple_xor\n"); 1512 break; 1513 case RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ: 1514 printf("symmetric_toeplitz\n"); 1515 break; 1516 default: 1517 printf("Unknown function\n"); 1518 return; 1519 } 1520 1521 printf(" RSS key:\n"); 1522 if (rss_conf->key_len == 0) { 1523 printf(" none"); 1524 } else { 1525 printf(" key_len: %u\n", rss_conf->key_len); 1526 printf(" key: "); 1527 if (rss_conf->key == NULL) { 1528 printf("none"); 1529 } else { 1530 for (i = 0; i < rss_conf->key_len; i++) 1531 printf("%02X", rss_conf->key[i]); 1532 } 1533 } 1534 printf("\n"); 1535 1536 printf(" types:\n"); 1537 if (rss_conf->types == 0) { 1538 printf(" none\n"); 1539 return; 1540 } 1541 rss_types_display(rss_conf->types, TESTPMD_RSS_TYPES_CHAR_NUM_PER_LINE); 1542 } 1543 1544 static struct port_indirect_action * 1545 action_get_by_id(portid_t port_id, uint32_t id) 1546 { 1547 struct rte_port *port; 1548 struct port_indirect_action **ppia; 1549 struct port_indirect_action *pia = NULL; 1550 1551 if (port_id_is_invalid(port_id, ENABLED_WARN) || 1552 port_id == (portid_t)RTE_PORT_ALL) 1553 return NULL; 1554 port = &ports[port_id]; 1555 ppia = &port->actions_list; 1556 while (*ppia) { 1557 if ((*ppia)->id == id) { 1558 pia = *ppia; 1559 break; 1560 } 1561 ppia = &(*ppia)->next; 1562 } 1563 if (!pia) 1564 fprintf(stderr, 1565 "Failed to find indirect action #%u on port %u\n", 1566 id, port_id); 1567 return pia; 1568 } 1569 1570 static int 1571 action_alloc(portid_t port_id, uint32_t id, 1572 struct port_indirect_action **action) 1573 { 1574 struct rte_port *port; 1575 struct port_indirect_action **ppia; 1576 struct port_indirect_action *pia = NULL; 1577 1578 *action = NULL; 1579 if (port_id_is_invalid(port_id, ENABLED_WARN) || 1580 port_id == (portid_t)RTE_PORT_ALL) 1581 return -EINVAL; 1582 port = &ports[port_id]; 1583 if (id == UINT32_MAX) { 1584 /* taking first available ID */ 1585 if (port->actions_list) { 1586 if (port->actions_list->id == UINT32_MAX - 1) { 1587 fprintf(stderr, 1588 "Highest indirect action ID is already assigned, delete it first\n"); 1589 return -ENOMEM; 1590 } 1591 id = port->actions_list->id + 1; 1592 } else { 1593 id = 0; 1594 } 1595 } 1596 pia = calloc(1, sizeof(*pia)); 1597 if (!pia) { 1598 fprintf(stderr, 1599 "Allocation of port %u indirect action failed\n", 1600 port_id); 1601 return -ENOMEM; 1602 } 1603 ppia = &port->actions_list; 1604 while (*ppia && (*ppia)->id > id) 1605 ppia = &(*ppia)->next; 1606 if (*ppia && (*ppia)->id == id) { 1607 fprintf(stderr, 1608 "Indirect action #%u is already assigned, delete it first\n", 1609 id); 1610 free(pia); 1611 return -EINVAL; 1612 } 1613 pia->next = *ppia; 1614 pia->id = id; 1615 *ppia = pia; 1616 *action = pia; 1617 return 0; 1618 } 1619 1620 static int 1621 template_alloc(uint32_t id, struct port_template **template, 1622 struct port_template **list) 1623 { 1624 struct port_template *lst = *list; 1625 struct port_template **ppt; 1626 struct port_template *pt = NULL; 1627 1628 *template = NULL; 1629 if (id == UINT32_MAX) { 1630 /* taking first available ID */ 1631 if (lst) { 1632 if (lst->id == UINT32_MAX - 1) { 1633 printf("Highest template ID is already" 1634 " assigned, delete it first\n"); 1635 return -ENOMEM; 1636 } 1637 id = lst->id + 1; 1638 } else { 1639 id = 0; 1640 } 1641 } 1642 pt = calloc(1, sizeof(*pt)); 1643 if (!pt) { 1644 printf("Allocation of port template failed\n"); 1645 return -ENOMEM; 1646 } 1647 ppt = list; 1648 while (*ppt && (*ppt)->id > id) 1649 ppt = &(*ppt)->next; 1650 if (*ppt && (*ppt)->id == id) { 1651 printf("Template #%u is already assigned," 1652 " delete it first\n", id); 1653 free(pt); 1654 return -EINVAL; 1655 } 1656 pt->next = *ppt; 1657 pt->id = id; 1658 *ppt = pt; 1659 *template = pt; 1660 return 0; 1661 } 1662 1663 static int 1664 table_alloc(uint32_t id, struct port_table **table, 1665 struct port_table **list) 1666 { 1667 struct port_table *lst = *list; 1668 struct port_table **ppt; 1669 struct port_table *pt = NULL; 1670 1671 *table = NULL; 1672 if (id == UINT32_MAX) { 1673 /* taking first available ID */ 1674 if (lst) { 1675 if (lst->id == UINT32_MAX - 1) { 1676 printf("Highest table ID is already" 1677 " assigned, delete it first\n"); 1678 return -ENOMEM; 1679 } 1680 id = lst->id + 1; 1681 } else { 1682 id = 0; 1683 } 1684 } 1685 pt = calloc(1, sizeof(*pt)); 1686 if (!pt) { 1687 printf("Allocation of table failed\n"); 1688 return -ENOMEM; 1689 } 1690 ppt = list; 1691 while (*ppt && (*ppt)->id > id) 1692 ppt = &(*ppt)->next; 1693 if (*ppt && (*ppt)->id == id) { 1694 printf("Table #%u is already assigned," 1695 " delete it first\n", id); 1696 free(pt); 1697 return -EINVAL; 1698 } 1699 pt->next = *ppt; 1700 pt->id = id; 1701 *ppt = pt; 1702 *table = pt; 1703 return 0; 1704 } 1705 1706 /** Get info about flow management resources. */ 1707 int 1708 port_flow_get_info(portid_t port_id) 1709 { 1710 struct rte_flow_port_info port_info; 1711 struct rte_flow_queue_info queue_info; 1712 struct rte_flow_error error; 1713 1714 if (port_id_is_invalid(port_id, ENABLED_WARN) || 1715 port_id == (portid_t)RTE_PORT_ALL) 1716 return -EINVAL; 1717 /* Poisoning to make sure PMDs update it in case of error. */ 1718 memset(&error, 0x99, sizeof(error)); 1719 memset(&port_info, 0, sizeof(port_info)); 1720 memset(&queue_info, 0, sizeof(queue_info)); 1721 if (rte_flow_info_get(port_id, &port_info, &queue_info, &error)) 1722 return port_flow_complain(&error); 1723 printf("Flow engine resources on port %u:\n" 1724 "Number of queues: %d\n" 1725 "Size of queues: %d\n" 1726 "Number of counters: %d\n" 1727 "Number of aging objects: %d\n" 1728 "Number of meter actions: %d\n", 1729 port_id, port_info.max_nb_queues, 1730 queue_info.max_size, 1731 port_info.max_nb_counters, 1732 port_info.max_nb_aging_objects, 1733 port_info.max_nb_meters); 1734 return 0; 1735 } 1736 1737 /** Configure flow management resources. */ 1738 int 1739 port_flow_configure(portid_t port_id, 1740 const struct rte_flow_port_attr *port_attr, 1741 uint16_t nb_queue, 1742 const struct rte_flow_queue_attr *queue_attr) 1743 { 1744 struct rte_port *port; 1745 struct rte_flow_error error; 1746 const struct rte_flow_queue_attr *attr_list[nb_queue]; 1747 int std_queue; 1748 1749 if (port_id_is_invalid(port_id, ENABLED_WARN) || 1750 port_id == (portid_t)RTE_PORT_ALL) 1751 return -EINVAL; 1752 port = &ports[port_id]; 1753 port->queue_nb = nb_queue; 1754 port->queue_sz = queue_attr->size; 1755 for (std_queue = 0; std_queue < nb_queue; std_queue++) 1756 attr_list[std_queue] = queue_attr; 1757 /* Poisoning to make sure PMDs update it in case of error. */ 1758 memset(&error, 0x66, sizeof(error)); 1759 if (rte_flow_configure(port_id, port_attr, nb_queue, attr_list, &error)) 1760 return port_flow_complain(&error); 1761 printf("Configure flows on port %u: " 1762 "number of queues %d with %d elements\n", 1763 port_id, nb_queue, queue_attr->size); 1764 return 0; 1765 } 1766 1767 static int 1768 action_handle_create(portid_t port_id, 1769 struct port_indirect_action *pia, 1770 const struct rte_flow_indir_action_conf *conf, 1771 const struct rte_flow_action *action, 1772 struct rte_flow_error *error) 1773 { 1774 if (action->type == RTE_FLOW_ACTION_TYPE_AGE) { 1775 struct rte_flow_action_age *age = 1776 (struct rte_flow_action_age *)(uintptr_t)(action->conf); 1777 1778 pia->age_type = ACTION_AGE_CONTEXT_TYPE_INDIRECT_ACTION; 1779 age->context = &pia->age_type; 1780 } else if (action->type == RTE_FLOW_ACTION_TYPE_CONNTRACK) { 1781 struct rte_flow_action_conntrack *ct = 1782 (struct rte_flow_action_conntrack *)(uintptr_t)(action->conf); 1783 1784 memcpy(ct, &conntrack_context, sizeof(*ct)); 1785 } 1786 pia->type = action->type; 1787 pia->handle = rte_flow_action_handle_create(port_id, conf, action, 1788 error); 1789 return pia->handle ? 0 : -1; 1790 } 1791 1792 static int 1793 action_list_handle_create(portid_t port_id, 1794 struct port_indirect_action *pia, 1795 const struct rte_flow_indir_action_conf *conf, 1796 const struct rte_flow_action *actions, 1797 struct rte_flow_error *error) 1798 { 1799 pia->type = RTE_FLOW_ACTION_TYPE_INDIRECT_LIST; 1800 pia->list_handle = 1801 rte_flow_action_list_handle_create(port_id, conf, 1802 actions, error); 1803 return pia->list_handle ? 0 : -1; 1804 } 1805 /** Create indirect action */ 1806 int 1807 port_action_handle_create(portid_t port_id, uint32_t id, bool indirect_list, 1808 const struct rte_flow_indir_action_conf *conf, 1809 const struct rte_flow_action *action) 1810 { 1811 struct port_indirect_action *pia; 1812 int ret; 1813 struct rte_flow_error error; 1814 1815 ret = action_alloc(port_id, id, &pia); 1816 if (ret) 1817 return ret; 1818 /* Poisoning to make sure PMDs update it in case of error. */ 1819 memset(&error, 0x22, sizeof(error)); 1820 ret = indirect_list ? 1821 action_list_handle_create(port_id, pia, conf, action, &error) : 1822 action_handle_create(port_id, pia, conf, action, &error); 1823 if (ret) { 1824 uint32_t destroy_id = pia->id; 1825 port_action_handle_destroy(port_id, 1, &destroy_id); 1826 return port_flow_complain(&error); 1827 } 1828 printf("Indirect action #%u created\n", pia->id); 1829 return 0; 1830 } 1831 1832 /** Destroy indirect action */ 1833 int 1834 port_action_handle_destroy(portid_t port_id, 1835 uint32_t n, 1836 const uint32_t *actions) 1837 { 1838 struct rte_port *port; 1839 struct port_indirect_action **tmp; 1840 int ret = 0; 1841 1842 if (port_id_is_invalid(port_id, ENABLED_WARN) || 1843 port_id == (portid_t)RTE_PORT_ALL) 1844 return -EINVAL; 1845 port = &ports[port_id]; 1846 tmp = &port->actions_list; 1847 while (*tmp) { 1848 uint32_t i; 1849 1850 for (i = 0; i != n; ++i) { 1851 struct rte_flow_error error; 1852 struct port_indirect_action *pia = *tmp; 1853 1854 if (actions[i] != pia->id) 1855 continue; 1856 /* 1857 * Poisoning to make sure PMDs update it in case 1858 * of error. 1859 */ 1860 memset(&error, 0x33, sizeof(error)); 1861 1862 if (pia->handle) { 1863 ret = pia->type == 1864 RTE_FLOW_ACTION_TYPE_INDIRECT_LIST ? 1865 rte_flow_action_list_handle_destroy 1866 (port_id, pia->list_handle, &error) : 1867 rte_flow_action_handle_destroy 1868 (port_id, pia->handle, &error); 1869 if (ret) { 1870 ret = port_flow_complain(&error); 1871 continue; 1872 } 1873 } 1874 *tmp = pia->next; 1875 printf("Indirect action #%u destroyed\n", pia->id); 1876 free(pia); 1877 break; 1878 } 1879 if (i == n) 1880 tmp = &(*tmp)->next; 1881 } 1882 return ret; 1883 } 1884 1885 int 1886 port_action_handle_flush(portid_t port_id) 1887 { 1888 struct rte_port *port; 1889 struct port_indirect_action **tmp; 1890 int ret = 0; 1891 1892 if (port_id_is_invalid(port_id, ENABLED_WARN) || 1893 port_id == (portid_t)RTE_PORT_ALL) 1894 return -EINVAL; 1895 port = &ports[port_id]; 1896 tmp = &port->actions_list; 1897 while (*tmp != NULL) { 1898 struct rte_flow_error error; 1899 struct port_indirect_action *pia = *tmp; 1900 1901 /* Poisoning to make sure PMDs update it in case of error. */ 1902 memset(&error, 0x44, sizeof(error)); 1903 if (pia->handle != NULL) { 1904 ret = pia->type == 1905 RTE_FLOW_ACTION_TYPE_INDIRECT_LIST ? 1906 rte_flow_action_list_handle_destroy 1907 (port_id, pia->list_handle, &error) : 1908 rte_flow_action_handle_destroy 1909 (port_id, pia->handle, &error); 1910 if (ret) { 1911 printf("Indirect action #%u not destroyed\n", 1912 pia->id); 1913 ret = port_flow_complain(&error); 1914 } 1915 tmp = &pia->next; 1916 } else { 1917 *tmp = pia->next; 1918 free(pia); 1919 } 1920 } 1921 return ret; 1922 } 1923 1924 /** Get indirect action by port + id */ 1925 struct rte_flow_action_handle * 1926 port_action_handle_get_by_id(portid_t port_id, uint32_t id) 1927 { 1928 1929 struct port_indirect_action *pia = action_get_by_id(port_id, id); 1930 1931 return (pia) ? pia->handle : NULL; 1932 } 1933 1934 /** Update indirect action */ 1935 int 1936 port_action_handle_update(portid_t port_id, uint32_t id, 1937 const struct rte_flow_action *action) 1938 { 1939 struct rte_flow_error error; 1940 struct rte_flow_action_handle *action_handle; 1941 struct port_indirect_action *pia; 1942 const void *update; 1943 1944 action_handle = port_action_handle_get_by_id(port_id, id); 1945 if (!action_handle) 1946 return -EINVAL; 1947 pia = action_get_by_id(port_id, id); 1948 if (!pia) 1949 return -EINVAL; 1950 switch (pia->type) { 1951 case RTE_FLOW_ACTION_TYPE_AGE: 1952 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 1953 update = action->conf; 1954 break; 1955 default: 1956 update = action; 1957 break; 1958 } 1959 if (rte_flow_action_handle_update(port_id, action_handle, update, 1960 &error)) { 1961 return port_flow_complain(&error); 1962 } 1963 printf("Indirect action #%u updated\n", id); 1964 return 0; 1965 } 1966 1967 static void 1968 port_action_handle_query_dump(portid_t port_id, 1969 const struct port_indirect_action *pia, 1970 union port_action_query *query) 1971 { 1972 if (!pia || !query) 1973 return; 1974 switch (pia->type) { 1975 case RTE_FLOW_ACTION_TYPE_AGE: 1976 printf("Indirect AGE action:\n" 1977 " aged: %u\n" 1978 " sec_since_last_hit_valid: %u\n" 1979 " sec_since_last_hit: %" PRIu32 "\n", 1980 query->age.aged, 1981 query->age.sec_since_last_hit_valid, 1982 query->age.sec_since_last_hit); 1983 break; 1984 case RTE_FLOW_ACTION_TYPE_COUNT: 1985 printf("Indirect COUNT action:\n" 1986 " hits_set: %u\n" 1987 " bytes_set: %u\n" 1988 " hits: %" PRIu64 "\n" 1989 " bytes: %" PRIu64 "\n", 1990 query->count.hits_set, 1991 query->count.bytes_set, 1992 query->count.hits, 1993 query->count.bytes); 1994 break; 1995 case RTE_FLOW_ACTION_TYPE_CONNTRACK: 1996 printf("Conntrack Context:\n" 1997 " Peer: %u, Flow dir: %s, Enable: %u\n" 1998 " Live: %u, SACK: %u, CACK: %u\n" 1999 " Packet dir: %s, Liberal: %u, State: %u\n" 2000 " Factor: %u, Retrans: %u, TCP flags: %u\n" 2001 " Last Seq: %u, Last ACK: %u\n" 2002 " Last Win: %u, Last End: %u\n", 2003 query->ct.peer_port, 2004 query->ct.is_original_dir ? "Original" : "Reply", 2005 query->ct.enable, query->ct.live_connection, 2006 query->ct.selective_ack, query->ct.challenge_ack_passed, 2007 query->ct.last_direction ? "Original" : "Reply", 2008 query->ct.liberal_mode, query->ct.state, 2009 query->ct.max_ack_window, query->ct.retransmission_limit, 2010 query->ct.last_index, query->ct.last_seq, 2011 query->ct.last_ack, query->ct.last_window, 2012 query->ct.last_end); 2013 printf(" Original Dir:\n" 2014 " scale: %u, fin: %u, ack seen: %u\n" 2015 " unacked data: %u\n Sent end: %u," 2016 " Reply end: %u, Max win: %u, Max ACK: %u\n", 2017 query->ct.original_dir.scale, 2018 query->ct.original_dir.close_initiated, 2019 query->ct.original_dir.last_ack_seen, 2020 query->ct.original_dir.data_unacked, 2021 query->ct.original_dir.sent_end, 2022 query->ct.original_dir.reply_end, 2023 query->ct.original_dir.max_win, 2024 query->ct.original_dir.max_ack); 2025 printf(" Reply Dir:\n" 2026 " scale: %u, fin: %u, ack seen: %u\n" 2027 " unacked data: %u\n Sent end: %u," 2028 " Reply end: %u, Max win: %u, Max ACK: %u\n", 2029 query->ct.reply_dir.scale, 2030 query->ct.reply_dir.close_initiated, 2031 query->ct.reply_dir.last_ack_seen, 2032 query->ct.reply_dir.data_unacked, 2033 query->ct.reply_dir.sent_end, 2034 query->ct.reply_dir.reply_end, 2035 query->ct.reply_dir.max_win, 2036 query->ct.reply_dir.max_ack); 2037 break; 2038 case RTE_FLOW_ACTION_TYPE_QUOTA: 2039 printf("Indirect QUOTA action %u\n" 2040 " unused quota: %" PRId64 "\n", 2041 pia->id, query->quota.quota); 2042 break; 2043 default: 2044 printf("port-%u: indirect action %u (type: %d) doesn't support query\n", 2045 pia->type, pia->id, port_id); 2046 break; 2047 } 2048 2049 } 2050 2051 void 2052 port_action_handle_query_update(portid_t port_id, uint32_t id, 2053 enum rte_flow_query_update_mode qu_mode, 2054 const struct rte_flow_action *action) 2055 { 2056 int ret; 2057 struct rte_flow_error error; 2058 struct port_indirect_action *pia; 2059 union port_action_query query; 2060 2061 pia = action_get_by_id(port_id, id); 2062 if (!pia || !pia->handle) 2063 return; 2064 ret = rte_flow_action_handle_query_update(port_id, pia->handle, action, 2065 &query, qu_mode, &error); 2066 if (ret) 2067 port_flow_complain(&error); 2068 else 2069 port_action_handle_query_dump(port_id, pia, &query); 2070 2071 } 2072 2073 int 2074 port_action_handle_query(portid_t port_id, uint32_t id) 2075 { 2076 struct rte_flow_error error; 2077 struct port_indirect_action *pia; 2078 union port_action_query query; 2079 2080 pia = action_get_by_id(port_id, id); 2081 if (!pia) 2082 return -EINVAL; 2083 switch (pia->type) { 2084 case RTE_FLOW_ACTION_TYPE_AGE: 2085 case RTE_FLOW_ACTION_TYPE_COUNT: 2086 case RTE_FLOW_ACTION_TYPE_QUOTA: 2087 break; 2088 default: 2089 fprintf(stderr, 2090 "Indirect action %u (type: %d) on port %u doesn't support query\n", 2091 id, pia->type, port_id); 2092 return -ENOTSUP; 2093 } 2094 /* Poisoning to make sure PMDs update it in case of error. */ 2095 memset(&error, 0x55, sizeof(error)); 2096 memset(&query, 0, sizeof(query)); 2097 if (rte_flow_action_handle_query(port_id, pia->handle, &query, &error)) 2098 return port_flow_complain(&error); 2099 port_action_handle_query_dump(port_id, pia, &query); 2100 return 0; 2101 } 2102 2103 static struct port_flow_tunnel * 2104 port_flow_tunnel_offload_cmd_prep(portid_t port_id, 2105 const struct rte_flow_item *pattern, 2106 const struct rte_flow_action *actions, 2107 const struct tunnel_ops *tunnel_ops) 2108 { 2109 int ret; 2110 struct rte_port *port; 2111 struct port_flow_tunnel *pft; 2112 struct rte_flow_error error; 2113 2114 port = &ports[port_id]; 2115 pft = port_flow_locate_tunnel_id(port, tunnel_ops->id); 2116 if (!pft) { 2117 fprintf(stderr, "failed to locate port flow tunnel #%u\n", 2118 tunnel_ops->id); 2119 return NULL; 2120 } 2121 if (tunnel_ops->actions) { 2122 uint32_t num_actions; 2123 const struct rte_flow_action *aptr; 2124 2125 ret = rte_flow_tunnel_decap_set(port_id, &pft->tunnel, 2126 &pft->pmd_actions, 2127 &pft->num_pmd_actions, 2128 &error); 2129 if (ret) { 2130 port_flow_complain(&error); 2131 return NULL; 2132 } 2133 for (aptr = actions, num_actions = 1; 2134 aptr->type != RTE_FLOW_ACTION_TYPE_END; 2135 aptr++, num_actions++); 2136 pft->actions = malloc( 2137 (num_actions + pft->num_pmd_actions) * 2138 sizeof(actions[0])); 2139 if (!pft->actions) { 2140 rte_flow_tunnel_action_decap_release( 2141 port_id, pft->actions, 2142 pft->num_pmd_actions, &error); 2143 return NULL; 2144 } 2145 rte_memcpy(pft->actions, pft->pmd_actions, 2146 pft->num_pmd_actions * sizeof(actions[0])); 2147 rte_memcpy(pft->actions + pft->num_pmd_actions, actions, 2148 num_actions * sizeof(actions[0])); 2149 } 2150 if (tunnel_ops->items) { 2151 uint32_t num_items; 2152 const struct rte_flow_item *iptr; 2153 2154 ret = rte_flow_tunnel_match(port_id, &pft->tunnel, 2155 &pft->pmd_items, 2156 &pft->num_pmd_items, 2157 &error); 2158 if (ret) { 2159 port_flow_complain(&error); 2160 return NULL; 2161 } 2162 for (iptr = pattern, num_items = 1; 2163 iptr->type != RTE_FLOW_ITEM_TYPE_END; 2164 iptr++, num_items++); 2165 pft->items = malloc((num_items + pft->num_pmd_items) * 2166 sizeof(pattern[0])); 2167 if (!pft->items) { 2168 rte_flow_tunnel_item_release( 2169 port_id, pft->pmd_items, 2170 pft->num_pmd_items, &error); 2171 return NULL; 2172 } 2173 rte_memcpy(pft->items, pft->pmd_items, 2174 pft->num_pmd_items * sizeof(pattern[0])); 2175 rte_memcpy(pft->items + pft->num_pmd_items, pattern, 2176 num_items * sizeof(pattern[0])); 2177 } 2178 2179 return pft; 2180 } 2181 2182 static void 2183 port_flow_tunnel_offload_cmd_release(portid_t port_id, 2184 const struct tunnel_ops *tunnel_ops, 2185 struct port_flow_tunnel *pft) 2186 { 2187 struct rte_flow_error error; 2188 2189 if (tunnel_ops->actions) { 2190 free(pft->actions); 2191 rte_flow_tunnel_action_decap_release( 2192 port_id, pft->pmd_actions, 2193 pft->num_pmd_actions, &error); 2194 pft->actions = NULL; 2195 pft->pmd_actions = NULL; 2196 } 2197 if (tunnel_ops->items) { 2198 free(pft->items); 2199 rte_flow_tunnel_item_release(port_id, pft->pmd_items, 2200 pft->num_pmd_items, 2201 &error); 2202 pft->items = NULL; 2203 pft->pmd_items = NULL; 2204 } 2205 } 2206 2207 /** Add port meter policy */ 2208 int 2209 port_meter_policy_add(portid_t port_id, uint32_t policy_id, 2210 const struct rte_flow_action *actions) 2211 { 2212 struct rte_mtr_error error; 2213 const struct rte_flow_action *act = actions; 2214 const struct rte_flow_action *start; 2215 struct rte_mtr_meter_policy_params policy; 2216 uint32_t i = 0, act_n; 2217 int ret; 2218 2219 for (i = 0; i < RTE_COLORS; i++) { 2220 for (act_n = 0, start = act; 2221 act->type != RTE_FLOW_ACTION_TYPE_END; act++) 2222 act_n++; 2223 if (act_n && act->type == RTE_FLOW_ACTION_TYPE_END) 2224 policy.actions[i] = start; 2225 else 2226 policy.actions[i] = NULL; 2227 act++; 2228 } 2229 ret = rte_mtr_meter_policy_add(port_id, 2230 policy_id, 2231 &policy, &error); 2232 if (ret) 2233 print_mtr_err_msg(&error); 2234 return ret; 2235 } 2236 2237 struct rte_flow_meter_profile * 2238 port_meter_profile_get_by_id(portid_t port_id, uint32_t id) 2239 { 2240 struct rte_mtr_error error; 2241 struct rte_flow_meter_profile *profile; 2242 2243 profile = rte_mtr_meter_profile_get(port_id, id, &error); 2244 if (!profile) 2245 print_mtr_err_msg(&error); 2246 return profile; 2247 } 2248 struct rte_flow_meter_policy * 2249 port_meter_policy_get_by_id(portid_t port_id, uint32_t id) 2250 { 2251 struct rte_mtr_error error; 2252 struct rte_flow_meter_policy *policy; 2253 2254 policy = rte_mtr_meter_policy_get(port_id, id, &error); 2255 if (!policy) 2256 print_mtr_err_msg(&error); 2257 return policy; 2258 } 2259 2260 /** Validate flow rule. */ 2261 int 2262 port_flow_validate(portid_t port_id, 2263 const struct rte_flow_attr *attr, 2264 const struct rte_flow_item *pattern, 2265 const struct rte_flow_action *actions, 2266 const struct tunnel_ops *tunnel_ops) 2267 { 2268 struct rte_flow_error error; 2269 struct port_flow_tunnel *pft = NULL; 2270 int ret; 2271 2272 /* Poisoning to make sure PMDs update it in case of error. */ 2273 memset(&error, 0x11, sizeof(error)); 2274 if (tunnel_ops->enabled) { 2275 pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern, 2276 actions, tunnel_ops); 2277 if (!pft) 2278 return -ENOENT; 2279 if (pft->items) 2280 pattern = pft->items; 2281 if (pft->actions) 2282 actions = pft->actions; 2283 } 2284 ret = rte_flow_validate(port_id, attr, pattern, actions, &error); 2285 if (tunnel_ops->enabled) 2286 port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); 2287 if (ret) 2288 return port_flow_complain(&error); 2289 printf("Flow rule validated\n"); 2290 return 0; 2291 } 2292 2293 /** Return age action structure if exists, otherwise NULL. */ 2294 static struct rte_flow_action_age * 2295 age_action_get(const struct rte_flow_action *actions) 2296 { 2297 for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { 2298 switch (actions->type) { 2299 case RTE_FLOW_ACTION_TYPE_AGE: 2300 return (struct rte_flow_action_age *) 2301 (uintptr_t)actions->conf; 2302 default: 2303 break; 2304 } 2305 } 2306 return NULL; 2307 } 2308 2309 /** Create pattern template */ 2310 int 2311 port_flow_pattern_template_create(portid_t port_id, uint32_t id, 2312 const struct rte_flow_pattern_template_attr *attr, 2313 const struct rte_flow_item *pattern) 2314 { 2315 struct rte_port *port; 2316 struct port_template *pit; 2317 int ret; 2318 struct rte_flow_error error; 2319 2320 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2321 port_id == (portid_t)RTE_PORT_ALL) 2322 return -EINVAL; 2323 port = &ports[port_id]; 2324 ret = template_alloc(id, &pit, &port->pattern_templ_list); 2325 if (ret) 2326 return ret; 2327 /* Poisoning to make sure PMDs update it in case of error. */ 2328 memset(&error, 0x22, sizeof(error)); 2329 pit->template.pattern_template = rte_flow_pattern_template_create(port_id, 2330 attr, pattern, &error); 2331 if (!pit->template.pattern_template) { 2332 uint32_t destroy_id = pit->id; 2333 port_flow_pattern_template_destroy(port_id, 1, &destroy_id); 2334 return port_flow_complain(&error); 2335 } 2336 printf("Pattern template #%u created\n", pit->id); 2337 return 0; 2338 } 2339 2340 /** Destroy pattern template */ 2341 int 2342 port_flow_pattern_template_destroy(portid_t port_id, uint32_t n, 2343 const uint32_t *template) 2344 { 2345 struct rte_port *port; 2346 struct port_template **tmp; 2347 int ret = 0; 2348 2349 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2350 port_id == (portid_t)RTE_PORT_ALL) 2351 return -EINVAL; 2352 port = &ports[port_id]; 2353 tmp = &port->pattern_templ_list; 2354 while (*tmp) { 2355 uint32_t i; 2356 2357 for (i = 0; i != n; ++i) { 2358 struct rte_flow_error error; 2359 struct port_template *pit = *tmp; 2360 2361 if (template[i] != pit->id) 2362 continue; 2363 /* 2364 * Poisoning to make sure PMDs update it in case 2365 * of error. 2366 */ 2367 memset(&error, 0x33, sizeof(error)); 2368 2369 if (pit->template.pattern_template && 2370 rte_flow_pattern_template_destroy(port_id, 2371 pit->template.pattern_template, 2372 &error)) { 2373 ret = port_flow_complain(&error); 2374 continue; 2375 } 2376 *tmp = pit->next; 2377 printf("Pattern template #%u destroyed\n", pit->id); 2378 free(pit); 2379 break; 2380 } 2381 if (i == n) 2382 tmp = &(*tmp)->next; 2383 } 2384 return ret; 2385 } 2386 2387 /** Flush pattern template */ 2388 int 2389 port_flow_pattern_template_flush(portid_t port_id) 2390 { 2391 struct rte_port *port; 2392 struct port_template **tmp; 2393 int ret = 0; 2394 2395 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2396 port_id == (portid_t)RTE_PORT_ALL) 2397 return -EINVAL; 2398 port = &ports[port_id]; 2399 tmp = &port->pattern_templ_list; 2400 while (*tmp) { 2401 struct rte_flow_error error; 2402 struct port_template *pit = *tmp; 2403 2404 /* 2405 * Poisoning to make sure PMDs update it in case 2406 * of error. 2407 */ 2408 memset(&error, 0x33, sizeof(error)); 2409 if (pit->template.pattern_template && 2410 rte_flow_pattern_template_destroy(port_id, 2411 pit->template.pattern_template, &error)) { 2412 printf("Pattern template #%u not destroyed\n", pit->id); 2413 ret = port_flow_complain(&error); 2414 tmp = &pit->next; 2415 } else { 2416 *tmp = pit->next; 2417 free(pit); 2418 } 2419 } 2420 return ret; 2421 } 2422 2423 /** Create actions template */ 2424 int 2425 port_flow_actions_template_create(portid_t port_id, uint32_t id, 2426 const struct rte_flow_actions_template_attr *attr, 2427 const struct rte_flow_action *actions, 2428 const struct rte_flow_action *masks) 2429 { 2430 struct rte_port *port; 2431 struct port_template *pat; 2432 int ret; 2433 struct rte_flow_error error; 2434 2435 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2436 port_id == (portid_t)RTE_PORT_ALL) 2437 return -EINVAL; 2438 port = &ports[port_id]; 2439 ret = template_alloc(id, &pat, &port->actions_templ_list); 2440 if (ret) 2441 return ret; 2442 /* Poisoning to make sure PMDs update it in case of error. */ 2443 memset(&error, 0x22, sizeof(error)); 2444 pat->template.actions_template = rte_flow_actions_template_create(port_id, 2445 attr, actions, masks, &error); 2446 if (!pat->template.actions_template) { 2447 uint32_t destroy_id = pat->id; 2448 port_flow_actions_template_destroy(port_id, 1, &destroy_id); 2449 return port_flow_complain(&error); 2450 } 2451 printf("Actions template #%u created\n", pat->id); 2452 return 0; 2453 } 2454 2455 /** Destroy actions template */ 2456 int 2457 port_flow_actions_template_destroy(portid_t port_id, uint32_t n, 2458 const uint32_t *template) 2459 { 2460 struct rte_port *port; 2461 struct port_template **tmp; 2462 int ret = 0; 2463 2464 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2465 port_id == (portid_t)RTE_PORT_ALL) 2466 return -EINVAL; 2467 port = &ports[port_id]; 2468 tmp = &port->actions_templ_list; 2469 while (*tmp) { 2470 uint32_t i; 2471 2472 for (i = 0; i != n; ++i) { 2473 struct rte_flow_error error; 2474 struct port_template *pat = *tmp; 2475 2476 if (template[i] != pat->id) 2477 continue; 2478 /* 2479 * Poisoning to make sure PMDs update it in case 2480 * of error. 2481 */ 2482 memset(&error, 0x33, sizeof(error)); 2483 2484 if (pat->template.actions_template && 2485 rte_flow_actions_template_destroy(port_id, 2486 pat->template.actions_template, &error)) { 2487 ret = port_flow_complain(&error); 2488 continue; 2489 } 2490 *tmp = pat->next; 2491 printf("Actions template #%u destroyed\n", pat->id); 2492 free(pat); 2493 break; 2494 } 2495 if (i == n) 2496 tmp = &(*tmp)->next; 2497 } 2498 return ret; 2499 } 2500 2501 /** Flush actions template */ 2502 int 2503 port_flow_actions_template_flush(portid_t port_id) 2504 { 2505 struct rte_port *port; 2506 struct port_template **tmp; 2507 int ret = 0; 2508 2509 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2510 port_id == (portid_t)RTE_PORT_ALL) 2511 return -EINVAL; 2512 port = &ports[port_id]; 2513 tmp = &port->actions_templ_list; 2514 while (*tmp) { 2515 struct rte_flow_error error; 2516 struct port_template *pat = *tmp; 2517 2518 /* 2519 * Poisoning to make sure PMDs update it in case 2520 * of error. 2521 */ 2522 memset(&error, 0x33, sizeof(error)); 2523 2524 if (pat->template.actions_template && 2525 rte_flow_actions_template_destroy(port_id, 2526 pat->template.actions_template, &error)) { 2527 ret = port_flow_complain(&error); 2528 printf("Actions template #%u not destroyed\n", pat->id); 2529 tmp = &pat->next; 2530 } else { 2531 *tmp = pat->next; 2532 free(pat); 2533 } 2534 } 2535 return ret; 2536 } 2537 2538 /** Create table */ 2539 int 2540 port_flow_template_table_create(portid_t port_id, uint32_t id, 2541 const struct rte_flow_template_table_attr *table_attr, 2542 uint32_t nb_pattern_templates, uint32_t *pattern_templates, 2543 uint32_t nb_actions_templates, uint32_t *actions_templates) 2544 { 2545 struct rte_port *port; 2546 struct port_table *pt; 2547 struct port_template *temp = NULL; 2548 int ret; 2549 uint32_t i; 2550 struct rte_flow_error error; 2551 struct rte_flow_pattern_template 2552 *flow_pattern_templates[nb_pattern_templates]; 2553 struct rte_flow_actions_template 2554 *flow_actions_templates[nb_actions_templates]; 2555 2556 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2557 port_id == (portid_t)RTE_PORT_ALL) 2558 return -EINVAL; 2559 port = &ports[port_id]; 2560 for (i = 0; i < nb_pattern_templates; ++i) { 2561 bool found = false; 2562 temp = port->pattern_templ_list; 2563 while (temp) { 2564 if (pattern_templates[i] == temp->id) { 2565 flow_pattern_templates[i] = 2566 temp->template.pattern_template; 2567 found = true; 2568 break; 2569 } 2570 temp = temp->next; 2571 } 2572 if (!found) { 2573 printf("Pattern template #%u is invalid\n", 2574 pattern_templates[i]); 2575 return -EINVAL; 2576 } 2577 } 2578 for (i = 0; i < nb_actions_templates; ++i) { 2579 bool found = false; 2580 temp = port->actions_templ_list; 2581 while (temp) { 2582 if (actions_templates[i] == temp->id) { 2583 flow_actions_templates[i] = 2584 temp->template.actions_template; 2585 found = true; 2586 break; 2587 } 2588 temp = temp->next; 2589 } 2590 if (!found) { 2591 printf("Actions template #%u is invalid\n", 2592 actions_templates[i]); 2593 return -EINVAL; 2594 } 2595 } 2596 ret = table_alloc(id, &pt, &port->table_list); 2597 if (ret) 2598 return ret; 2599 /* Poisoning to make sure PMDs update it in case of error. */ 2600 memset(&error, 0x22, sizeof(error)); 2601 pt->table = rte_flow_template_table_create(port_id, table_attr, 2602 flow_pattern_templates, nb_pattern_templates, 2603 flow_actions_templates, nb_actions_templates, 2604 &error); 2605 2606 if (!pt->table) { 2607 uint32_t destroy_id = pt->id; 2608 port_flow_template_table_destroy(port_id, 1, &destroy_id); 2609 return port_flow_complain(&error); 2610 } 2611 pt->nb_pattern_templates = nb_pattern_templates; 2612 pt->nb_actions_templates = nb_actions_templates; 2613 rte_memcpy(&pt->flow_attr, &table_attr->flow_attr, 2614 sizeof(struct rte_flow_attr)); 2615 printf("Template table #%u created\n", pt->id); 2616 return 0; 2617 } 2618 2619 /** Destroy table */ 2620 int 2621 port_flow_template_table_destroy(portid_t port_id, 2622 uint32_t n, const uint32_t *table) 2623 { 2624 struct rte_port *port; 2625 struct port_table **tmp; 2626 int ret = 0; 2627 2628 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2629 port_id == (portid_t)RTE_PORT_ALL) 2630 return -EINVAL; 2631 port = &ports[port_id]; 2632 tmp = &port->table_list; 2633 while (*tmp) { 2634 uint32_t i; 2635 2636 for (i = 0; i != n; ++i) { 2637 struct rte_flow_error error; 2638 struct port_table *pt = *tmp; 2639 2640 if (table[i] != pt->id) 2641 continue; 2642 /* 2643 * Poisoning to make sure PMDs update it in case 2644 * of error. 2645 */ 2646 memset(&error, 0x33, sizeof(error)); 2647 2648 if (pt->table && 2649 rte_flow_template_table_destroy(port_id, 2650 pt->table, 2651 &error)) { 2652 ret = port_flow_complain(&error); 2653 continue; 2654 } 2655 *tmp = pt->next; 2656 printf("Template table #%u destroyed\n", pt->id); 2657 free(pt); 2658 break; 2659 } 2660 if (i == n) 2661 tmp = &(*tmp)->next; 2662 } 2663 return ret; 2664 } 2665 2666 /** Flush table */ 2667 int 2668 port_flow_template_table_flush(portid_t port_id) 2669 { 2670 struct rte_port *port; 2671 struct port_table **tmp; 2672 int ret = 0; 2673 2674 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2675 port_id == (portid_t)RTE_PORT_ALL) 2676 return -EINVAL; 2677 port = &ports[port_id]; 2678 tmp = &port->table_list; 2679 while (*tmp) { 2680 struct rte_flow_error error; 2681 struct port_table *pt = *tmp; 2682 2683 /* 2684 * Poisoning to make sure PMDs update it in case 2685 * of error. 2686 */ 2687 memset(&error, 0x33, sizeof(error)); 2688 2689 if (pt->table && 2690 rte_flow_template_table_destroy(port_id, 2691 pt->table, 2692 &error)) { 2693 ret = port_flow_complain(&error); 2694 printf("Template table #%u not destroyed\n", pt->id); 2695 tmp = &pt->next; 2696 } else { 2697 *tmp = pt->next; 2698 free(pt); 2699 } 2700 } 2701 return ret; 2702 } 2703 2704 /** Enqueue create flow rule operation. */ 2705 int 2706 port_queue_flow_create(portid_t port_id, queueid_t queue_id, 2707 bool postpone, uint32_t table_id, uint32_t rule_idx, 2708 uint32_t pattern_idx, uint32_t actions_idx, 2709 const struct rte_flow_item *pattern, 2710 const struct rte_flow_action *actions) 2711 { 2712 struct rte_flow_op_attr op_attr = { .postpone = postpone }; 2713 struct rte_flow *flow; 2714 struct rte_port *port; 2715 struct port_flow *pf; 2716 struct port_table *pt; 2717 uint32_t id = 0; 2718 bool found; 2719 struct rte_flow_error error = { RTE_FLOW_ERROR_TYPE_NONE, NULL, NULL }; 2720 struct rte_flow_action_age *age = age_action_get(actions); 2721 struct queue_job *job; 2722 2723 port = &ports[port_id]; 2724 if (port->flow_list) { 2725 if (port->flow_list->id == UINT32_MAX) { 2726 printf("Highest rule ID is already assigned," 2727 " delete it first"); 2728 return -ENOMEM; 2729 } 2730 id = port->flow_list->id + 1; 2731 } 2732 2733 if (queue_id >= port->queue_nb) { 2734 printf("Queue #%u is invalid\n", queue_id); 2735 return -EINVAL; 2736 } 2737 2738 found = false; 2739 pt = port->table_list; 2740 while (pt) { 2741 if (table_id == pt->id) { 2742 found = true; 2743 break; 2744 } 2745 pt = pt->next; 2746 } 2747 if (!found) { 2748 printf("Table #%u is invalid\n", table_id); 2749 return -EINVAL; 2750 } 2751 2752 if (pattern_idx >= pt->nb_pattern_templates) { 2753 printf("Pattern template index #%u is invalid," 2754 " %u templates present in the table\n", 2755 pattern_idx, pt->nb_pattern_templates); 2756 return -EINVAL; 2757 } 2758 if (actions_idx >= pt->nb_actions_templates) { 2759 printf("Actions template index #%u is invalid," 2760 " %u templates present in the table\n", 2761 actions_idx, pt->nb_actions_templates); 2762 return -EINVAL; 2763 } 2764 2765 job = calloc(1, sizeof(*job)); 2766 if (!job) { 2767 printf("Queue flow create job allocate failed\n"); 2768 return -ENOMEM; 2769 } 2770 job->type = QUEUE_JOB_TYPE_FLOW_CREATE; 2771 2772 pf = port_flow_new(&pt->flow_attr, pattern, actions, &error); 2773 if (!pf) { 2774 free(job); 2775 return port_flow_complain(&error); 2776 } 2777 if (age) { 2778 pf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW; 2779 age->context = &pf->age_type; 2780 } 2781 /* Poisoning to make sure PMDs update it in case of error. */ 2782 memset(&error, 0x11, sizeof(error)); 2783 if (rule_idx == UINT32_MAX) 2784 flow = rte_flow_async_create(port_id, queue_id, &op_attr, pt->table, 2785 pattern, pattern_idx, actions, actions_idx, job, &error); 2786 else 2787 flow = rte_flow_async_create_by_index(port_id, queue_id, &op_attr, pt->table, 2788 rule_idx, actions, actions_idx, job, &error); 2789 if (!flow) { 2790 uint32_t flow_id = pf->id; 2791 port_queue_flow_destroy(port_id, queue_id, true, 1, &flow_id); 2792 free(job); 2793 return port_flow_complain(&error); 2794 } 2795 2796 pf->next = port->flow_list; 2797 pf->id = id; 2798 pf->flow = flow; 2799 job->pf = pf; 2800 port->flow_list = pf; 2801 printf("Flow rule #%u creation enqueued\n", pf->id); 2802 return 0; 2803 } 2804 2805 /** Enqueue number of destroy flow rules operations. */ 2806 int 2807 port_queue_flow_destroy(portid_t port_id, queueid_t queue_id, 2808 bool postpone, uint32_t n, const uint32_t *rule) 2809 { 2810 struct rte_flow_op_attr op_attr = { .postpone = postpone }; 2811 struct rte_port *port; 2812 struct port_flow **tmp; 2813 int ret = 0; 2814 struct queue_job *job; 2815 2816 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2817 port_id == (portid_t)RTE_PORT_ALL) 2818 return -EINVAL; 2819 port = &ports[port_id]; 2820 2821 if (queue_id >= port->queue_nb) { 2822 printf("Queue #%u is invalid\n", queue_id); 2823 return -EINVAL; 2824 } 2825 2826 tmp = &port->flow_list; 2827 while (*tmp) { 2828 uint32_t i; 2829 2830 for (i = 0; i != n; ++i) { 2831 struct rte_flow_error error; 2832 struct port_flow *pf = *tmp; 2833 2834 if (rule[i] != pf->id) 2835 continue; 2836 /* 2837 * Poisoning to make sure PMD 2838 * update it in case of error. 2839 */ 2840 memset(&error, 0x33, sizeof(error)); 2841 job = calloc(1, sizeof(*job)); 2842 if (!job) { 2843 printf("Queue flow destroy job allocate failed\n"); 2844 return -ENOMEM; 2845 } 2846 job->type = QUEUE_JOB_TYPE_FLOW_DESTROY; 2847 job->pf = pf; 2848 2849 if (rte_flow_async_destroy(port_id, queue_id, &op_attr, 2850 pf->flow, job, &error)) { 2851 free(job); 2852 ret = port_flow_complain(&error); 2853 continue; 2854 } 2855 printf("Flow rule #%u destruction enqueued\n", pf->id); 2856 *tmp = pf->next; 2857 break; 2858 } 2859 if (i == n) 2860 tmp = &(*tmp)->next; 2861 } 2862 return ret; 2863 } 2864 2865 static void 2866 queue_action_handle_create(portid_t port_id, uint32_t queue_id, 2867 struct port_indirect_action *pia, 2868 struct queue_job *job, 2869 const struct rte_flow_op_attr *attr, 2870 const struct rte_flow_indir_action_conf *conf, 2871 const struct rte_flow_action *action, 2872 struct rte_flow_error *error) 2873 { 2874 if (action->type == RTE_FLOW_ACTION_TYPE_AGE) { 2875 struct rte_flow_action_age *age = 2876 (struct rte_flow_action_age *)(uintptr_t)(action->conf); 2877 2878 pia->age_type = ACTION_AGE_CONTEXT_TYPE_INDIRECT_ACTION; 2879 age->context = &pia->age_type; 2880 } 2881 /* Poisoning to make sure PMDs update it in case of error. */ 2882 pia->handle = rte_flow_async_action_handle_create(port_id, queue_id, 2883 attr, conf, action, 2884 job, error); 2885 pia->type = action->type; 2886 } 2887 2888 static void 2889 queue_action_list_handle_create(portid_t port_id, uint32_t queue_id, 2890 struct port_indirect_action *pia, 2891 struct queue_job *job, 2892 const struct rte_flow_op_attr *attr, 2893 const struct rte_flow_indir_action_conf *conf, 2894 const struct rte_flow_action *action, 2895 struct rte_flow_error *error) 2896 { 2897 /* Poisoning to make sure PMDs update it in case of error. */ 2898 pia->type = RTE_FLOW_ACTION_TYPE_INDIRECT_LIST; 2899 pia->list_handle = rte_flow_async_action_list_handle_create 2900 (port_id, queue_id, attr, conf, action, 2901 job, error); 2902 } 2903 2904 /** Enqueue indirect action create operation. */ 2905 int 2906 port_queue_action_handle_create(portid_t port_id, uint32_t queue_id, 2907 bool postpone, uint32_t id, 2908 const struct rte_flow_indir_action_conf *conf, 2909 const struct rte_flow_action *action) 2910 { 2911 const struct rte_flow_op_attr attr = { .postpone = postpone}; 2912 struct rte_port *port; 2913 struct port_indirect_action *pia; 2914 int ret; 2915 struct rte_flow_error error; 2916 struct queue_job *job; 2917 bool is_indirect_list = action[1].type != RTE_FLOW_ACTION_TYPE_END; 2918 2919 2920 ret = action_alloc(port_id, id, &pia); 2921 if (ret) 2922 return ret; 2923 2924 port = &ports[port_id]; 2925 if (queue_id >= port->queue_nb) { 2926 printf("Queue #%u is invalid\n", queue_id); 2927 return -EINVAL; 2928 } 2929 job = calloc(1, sizeof(*job)); 2930 if (!job) { 2931 printf("Queue action create job allocate failed\n"); 2932 return -ENOMEM; 2933 } 2934 job->type = QUEUE_JOB_TYPE_ACTION_CREATE; 2935 job->pia = pia; 2936 2937 /* Poisoning to make sure PMDs update it in case of error. */ 2938 memset(&error, 0x88, sizeof(error)); 2939 2940 if (is_indirect_list) 2941 queue_action_list_handle_create(port_id, queue_id, pia, job, 2942 &attr, conf, action, &error); 2943 else 2944 queue_action_handle_create(port_id, queue_id, pia, job, &attr, 2945 conf, action, &error); 2946 2947 if (!pia->handle) { 2948 uint32_t destroy_id = pia->id; 2949 port_queue_action_handle_destroy(port_id, queue_id, 2950 postpone, 1, &destroy_id); 2951 free(job); 2952 return port_flow_complain(&error); 2953 } 2954 printf("Indirect action #%u creation queued\n", pia->id); 2955 return 0; 2956 } 2957 2958 /** Enqueue indirect action destroy operation. */ 2959 int 2960 port_queue_action_handle_destroy(portid_t port_id, 2961 uint32_t queue_id, bool postpone, 2962 uint32_t n, const uint32_t *actions) 2963 { 2964 const struct rte_flow_op_attr attr = { .postpone = postpone}; 2965 struct rte_port *port; 2966 struct port_indirect_action **tmp; 2967 int ret = 0; 2968 struct queue_job *job; 2969 2970 if (port_id_is_invalid(port_id, ENABLED_WARN) || 2971 port_id == (portid_t)RTE_PORT_ALL) 2972 return -EINVAL; 2973 port = &ports[port_id]; 2974 2975 if (queue_id >= port->queue_nb) { 2976 printf("Queue #%u is invalid\n", queue_id); 2977 return -EINVAL; 2978 } 2979 2980 tmp = &port->actions_list; 2981 while (*tmp) { 2982 uint32_t i; 2983 2984 for (i = 0; i != n; ++i) { 2985 struct rte_flow_error error; 2986 struct port_indirect_action *pia = *tmp; 2987 2988 if (actions[i] != pia->id) 2989 continue; 2990 /* 2991 * Poisoning to make sure PMDs update it in case 2992 * of error. 2993 */ 2994 memset(&error, 0x99, sizeof(error)); 2995 job = calloc(1, sizeof(*job)); 2996 if (!job) { 2997 printf("Queue action destroy job allocate failed\n"); 2998 return -ENOMEM; 2999 } 3000 job->type = QUEUE_JOB_TYPE_ACTION_DESTROY; 3001 job->pia = pia; 3002 ret = pia->type == RTE_FLOW_ACTION_TYPE_INDIRECT_LIST ? 3003 rte_flow_async_action_list_handle_destroy 3004 (port_id, queue_id, 3005 &attr, pia->list_handle, 3006 job, &error) : 3007 rte_flow_async_action_handle_destroy 3008 (port_id, queue_id, &attr, pia->handle, 3009 job, &error); 3010 if (ret) { 3011 free(job); 3012 ret = port_flow_complain(&error); 3013 continue; 3014 } 3015 *tmp = pia->next; 3016 printf("Indirect action #%u destruction queued\n", 3017 pia->id); 3018 break; 3019 } 3020 if (i == n) 3021 tmp = &(*tmp)->next; 3022 } 3023 return ret; 3024 } 3025 3026 /** Enqueue indirect action update operation. */ 3027 int 3028 port_queue_action_handle_update(portid_t port_id, 3029 uint32_t queue_id, bool postpone, uint32_t id, 3030 const struct rte_flow_action *action) 3031 { 3032 const struct rte_flow_op_attr attr = { .postpone = postpone}; 3033 struct rte_port *port; 3034 struct rte_flow_error error; 3035 struct rte_flow_action_handle *action_handle; 3036 struct queue_job *job; 3037 struct port_indirect_action *pia; 3038 struct rte_flow_update_meter_mark mtr_update; 3039 const void *update; 3040 3041 action_handle = port_action_handle_get_by_id(port_id, id); 3042 if (!action_handle) 3043 return -EINVAL; 3044 3045 port = &ports[port_id]; 3046 if (queue_id >= port->queue_nb) { 3047 printf("Queue #%u is invalid\n", queue_id); 3048 return -EINVAL; 3049 } 3050 3051 job = calloc(1, sizeof(*job)); 3052 if (!job) { 3053 printf("Queue action update job allocate failed\n"); 3054 return -ENOMEM; 3055 } 3056 job->type = QUEUE_JOB_TYPE_ACTION_UPDATE; 3057 3058 pia = action_get_by_id(port_id, id); 3059 if (!pia) { 3060 free(job); 3061 return -EINVAL; 3062 } 3063 3064 switch (pia->type) { 3065 case RTE_FLOW_ACTION_TYPE_AGE: 3066 update = action->conf; 3067 break; 3068 case RTE_FLOW_ACTION_TYPE_METER_MARK: 3069 rte_memcpy(&mtr_update.meter_mark, action->conf, 3070 sizeof(struct rte_flow_action_meter_mark)); 3071 mtr_update.profile_valid = 1; 3072 mtr_update.policy_valid = 1; 3073 mtr_update.color_mode_valid = 1; 3074 mtr_update.init_color_valid = 1; 3075 mtr_update.state_valid = 1; 3076 update = &mtr_update; 3077 break; 3078 default: 3079 update = action; 3080 break; 3081 } 3082 3083 if (rte_flow_async_action_handle_update(port_id, queue_id, &attr, 3084 action_handle, update, job, &error)) { 3085 free(job); 3086 return port_flow_complain(&error); 3087 } 3088 printf("Indirect action #%u update queued\n", id); 3089 return 0; 3090 } 3091 3092 void 3093 port_queue_action_handle_query_update(portid_t port_id, 3094 uint32_t queue_id, bool postpone, 3095 uint32_t id, 3096 enum rte_flow_query_update_mode qu_mode, 3097 const struct rte_flow_action *action) 3098 { 3099 int ret; 3100 struct rte_flow_error error; 3101 struct port_indirect_action *pia = action_get_by_id(port_id, id); 3102 const struct rte_flow_op_attr attr = { .postpone = postpone}; 3103 struct queue_job *job; 3104 3105 if (!pia || !pia->handle) 3106 return; 3107 job = calloc(1, sizeof(*job)); 3108 if (!job) 3109 return; 3110 job->type = QUEUE_JOB_TYPE_ACTION_QUERY; 3111 job->pia = pia; 3112 3113 ret = rte_flow_async_action_handle_query_update(port_id, queue_id, 3114 &attr, pia->handle, 3115 action, 3116 &job->query, 3117 qu_mode, job, 3118 &error); 3119 if (ret) { 3120 port_flow_complain(&error); 3121 free(job); 3122 } else { 3123 printf("port-%u: indirect action #%u update-and-query queued\n", 3124 port_id, id); 3125 } 3126 } 3127 3128 /** Enqueue indirect action query operation. */ 3129 int 3130 port_queue_action_handle_query(portid_t port_id, 3131 uint32_t queue_id, bool postpone, uint32_t id) 3132 { 3133 const struct rte_flow_op_attr attr = { .postpone = postpone}; 3134 struct rte_port *port; 3135 struct rte_flow_error error; 3136 struct rte_flow_action_handle *action_handle; 3137 struct port_indirect_action *pia; 3138 struct queue_job *job; 3139 3140 pia = action_get_by_id(port_id, id); 3141 action_handle = pia ? pia->handle : NULL; 3142 if (!action_handle) 3143 return -EINVAL; 3144 3145 port = &ports[port_id]; 3146 if (queue_id >= port->queue_nb) { 3147 printf("Queue #%u is invalid\n", queue_id); 3148 return -EINVAL; 3149 } 3150 3151 job = calloc(1, sizeof(*job)); 3152 if (!job) { 3153 printf("Queue action update job allocate failed\n"); 3154 return -ENOMEM; 3155 } 3156 job->type = QUEUE_JOB_TYPE_ACTION_QUERY; 3157 job->pia = pia; 3158 3159 if (rte_flow_async_action_handle_query(port_id, queue_id, &attr, 3160 action_handle, &job->query, job, &error)) { 3161 free(job); 3162 return port_flow_complain(&error); 3163 } 3164 printf("Indirect action #%u update queued\n", id); 3165 return 0; 3166 } 3167 3168 /** Push all the queue operations in the queue to the NIC. */ 3169 int 3170 port_queue_flow_push(portid_t port_id, queueid_t queue_id) 3171 { 3172 struct rte_port *port; 3173 struct rte_flow_error error; 3174 int ret = 0; 3175 3176 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3177 port_id == (portid_t)RTE_PORT_ALL) 3178 return -EINVAL; 3179 port = &ports[port_id]; 3180 3181 if (queue_id >= port->queue_nb) { 3182 printf("Queue #%u is invalid\n", queue_id); 3183 return -EINVAL; 3184 } 3185 3186 memset(&error, 0x55, sizeof(error)); 3187 ret = rte_flow_push(port_id, queue_id, &error); 3188 if (ret < 0) { 3189 printf("Failed to push operations in the queue\n"); 3190 return -EINVAL; 3191 } 3192 printf("Queue #%u operations pushed\n", queue_id); 3193 return ret; 3194 } 3195 3196 /** Pull queue operation results from the queue. */ 3197 static int 3198 port_queue_aged_flow_destroy(portid_t port_id, queueid_t queue_id, 3199 const uint32_t *rule, int nb_flows) 3200 { 3201 struct rte_port *port = &ports[port_id]; 3202 struct rte_flow_op_result *res; 3203 struct rte_flow_error error; 3204 uint32_t n = nb_flows; 3205 int ret = 0; 3206 int i; 3207 3208 res = calloc(port->queue_sz, sizeof(struct rte_flow_op_result)); 3209 if (!res) { 3210 printf("Failed to allocate memory for pulled results\n"); 3211 return -ENOMEM; 3212 } 3213 3214 memset(&error, 0x66, sizeof(error)); 3215 while (nb_flows > 0) { 3216 int success = 0; 3217 3218 if (n > port->queue_sz) 3219 n = port->queue_sz; 3220 ret = port_queue_flow_destroy(port_id, queue_id, true, n, rule); 3221 if (ret < 0) { 3222 free(res); 3223 return ret; 3224 } 3225 ret = rte_flow_push(port_id, queue_id, &error); 3226 if (ret < 0) { 3227 printf("Failed to push operations in the queue: %s\n", 3228 strerror(-ret)); 3229 free(res); 3230 return ret; 3231 } 3232 while (success < nb_flows) { 3233 ret = rte_flow_pull(port_id, queue_id, res, 3234 port->queue_sz, &error); 3235 if (ret < 0) { 3236 printf("Failed to pull a operation results: %s\n", 3237 strerror(-ret)); 3238 free(res); 3239 return ret; 3240 } 3241 3242 for (i = 0; i < ret; i++) { 3243 if (res[i].status == RTE_FLOW_OP_SUCCESS) 3244 success++; 3245 } 3246 } 3247 rule += n; 3248 nb_flows -= n; 3249 n = nb_flows; 3250 } 3251 3252 free(res); 3253 return ret; 3254 } 3255 3256 /** List simply and destroy all aged flows per queue. */ 3257 void 3258 port_queue_flow_aged(portid_t port_id, uint32_t queue_id, uint8_t destroy) 3259 { 3260 void **contexts; 3261 int nb_context, total = 0, idx; 3262 uint32_t *rules = NULL; 3263 struct rte_port *port; 3264 struct rte_flow_error error; 3265 enum age_action_context_type *type; 3266 union { 3267 struct port_flow *pf; 3268 struct port_indirect_action *pia; 3269 } ctx; 3270 3271 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3272 port_id == (portid_t)RTE_PORT_ALL) 3273 return; 3274 port = &ports[port_id]; 3275 if (queue_id >= port->queue_nb) { 3276 printf("Error: queue #%u is invalid\n", queue_id); 3277 return; 3278 } 3279 total = rte_flow_get_q_aged_flows(port_id, queue_id, NULL, 0, &error); 3280 if (total < 0) { 3281 port_flow_complain(&error); 3282 return; 3283 } 3284 printf("Port %u queue %u total aged flows: %d\n", 3285 port_id, queue_id, total); 3286 if (total == 0) 3287 return; 3288 contexts = calloc(total, sizeof(void *)); 3289 if (contexts == NULL) { 3290 printf("Cannot allocate contexts for aged flow\n"); 3291 return; 3292 } 3293 printf("%-20s\tID\tGroup\tPrio\tAttr\n", "Type"); 3294 nb_context = rte_flow_get_q_aged_flows(port_id, queue_id, contexts, 3295 total, &error); 3296 if (nb_context > total) { 3297 printf("Port %u queue %u get aged flows count(%d) > total(%d)\n", 3298 port_id, queue_id, nb_context, total); 3299 free(contexts); 3300 return; 3301 } 3302 if (destroy) { 3303 rules = malloc(sizeof(uint32_t) * nb_context); 3304 if (rules == NULL) 3305 printf("Cannot allocate memory for destroy aged flow\n"); 3306 } 3307 total = 0; 3308 for (idx = 0; idx < nb_context; idx++) { 3309 if (!contexts[idx]) { 3310 printf("Error: get Null context in port %u queue %u\n", 3311 port_id, queue_id); 3312 continue; 3313 } 3314 type = (enum age_action_context_type *)contexts[idx]; 3315 switch (*type) { 3316 case ACTION_AGE_CONTEXT_TYPE_FLOW: 3317 ctx.pf = container_of(type, struct port_flow, age_type); 3318 printf("%-20s\t%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 3319 "\t%c%c%c\t\n", 3320 "Flow", 3321 ctx.pf->id, 3322 ctx.pf->rule.attr->group, 3323 ctx.pf->rule.attr->priority, 3324 ctx.pf->rule.attr->ingress ? 'i' : '-', 3325 ctx.pf->rule.attr->egress ? 'e' : '-', 3326 ctx.pf->rule.attr->transfer ? 't' : '-'); 3327 if (rules != NULL) { 3328 rules[total] = ctx.pf->id; 3329 total++; 3330 } 3331 break; 3332 case ACTION_AGE_CONTEXT_TYPE_INDIRECT_ACTION: 3333 ctx.pia = container_of(type, 3334 struct port_indirect_action, 3335 age_type); 3336 printf("%-20s\t%" PRIu32 "\n", "Indirect action", 3337 ctx.pia->id); 3338 break; 3339 default: 3340 printf("Error: invalid context type %u\n", port_id); 3341 break; 3342 } 3343 } 3344 if (rules != NULL) { 3345 port_queue_aged_flow_destroy(port_id, queue_id, rules, total); 3346 free(rules); 3347 } 3348 printf("\n%d flows destroyed\n", total); 3349 free(contexts); 3350 } 3351 3352 /** Pull queue operation results from the queue. */ 3353 int 3354 port_queue_flow_pull(portid_t port_id, queueid_t queue_id) 3355 { 3356 struct rte_port *port; 3357 struct rte_flow_op_result *res; 3358 struct rte_flow_error error; 3359 int ret = 0; 3360 int success = 0; 3361 int i; 3362 struct queue_job *job; 3363 3364 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3365 port_id == (portid_t)RTE_PORT_ALL) 3366 return -EINVAL; 3367 port = &ports[port_id]; 3368 3369 if (queue_id >= port->queue_nb) { 3370 printf("Queue #%u is invalid\n", queue_id); 3371 return -EINVAL; 3372 } 3373 3374 res = calloc(port->queue_sz, sizeof(struct rte_flow_op_result)); 3375 if (!res) { 3376 printf("Failed to allocate memory for pulled results\n"); 3377 return -ENOMEM; 3378 } 3379 3380 memset(&error, 0x66, sizeof(error)); 3381 ret = rte_flow_pull(port_id, queue_id, res, 3382 port->queue_sz, &error); 3383 if (ret < 0) { 3384 printf("Failed to pull a operation results\n"); 3385 free(res); 3386 return -EINVAL; 3387 } 3388 3389 for (i = 0; i < ret; i++) { 3390 if (res[i].status == RTE_FLOW_OP_SUCCESS) 3391 success++; 3392 job = (struct queue_job *)res[i].user_data; 3393 if (job->type == QUEUE_JOB_TYPE_FLOW_DESTROY) 3394 free(job->pf); 3395 else if (job->type == QUEUE_JOB_TYPE_ACTION_DESTROY) 3396 free(job->pia); 3397 else if (job->type == QUEUE_JOB_TYPE_ACTION_QUERY) 3398 port_action_handle_query_dump(port_id, job->pia, 3399 &job->query); 3400 free(job); 3401 } 3402 printf("Queue #%u pulled %u operations (%u failed, %u succeeded)\n", 3403 queue_id, ret, ret - success, success); 3404 free(res); 3405 return ret; 3406 } 3407 3408 /** Create flow rule. */ 3409 int 3410 port_flow_create(portid_t port_id, 3411 const struct rte_flow_attr *attr, 3412 const struct rte_flow_item *pattern, 3413 const struct rte_flow_action *actions, 3414 const struct tunnel_ops *tunnel_ops) 3415 { 3416 struct rte_flow *flow; 3417 struct rte_port *port; 3418 struct port_flow *pf; 3419 uint32_t id = 0; 3420 struct rte_flow_error error; 3421 struct port_flow_tunnel *pft = NULL; 3422 struct rte_flow_action_age *age = age_action_get(actions); 3423 3424 port = &ports[port_id]; 3425 if (port->flow_list) { 3426 if (port->flow_list->id == UINT32_MAX) { 3427 fprintf(stderr, 3428 "Highest rule ID is already assigned, delete it first"); 3429 return -ENOMEM; 3430 } 3431 id = port->flow_list->id + 1; 3432 } 3433 if (tunnel_ops->enabled) { 3434 pft = port_flow_tunnel_offload_cmd_prep(port_id, pattern, 3435 actions, tunnel_ops); 3436 if (!pft) 3437 return -ENOENT; 3438 if (pft->items) 3439 pattern = pft->items; 3440 if (pft->actions) 3441 actions = pft->actions; 3442 } 3443 pf = port_flow_new(attr, pattern, actions, &error); 3444 if (!pf) 3445 return port_flow_complain(&error); 3446 if (age) { 3447 pf->age_type = ACTION_AGE_CONTEXT_TYPE_FLOW; 3448 age->context = &pf->age_type; 3449 } 3450 /* Poisoning to make sure PMDs update it in case of error. */ 3451 memset(&error, 0x22, sizeof(error)); 3452 flow = rte_flow_create(port_id, attr, pattern, actions, &error); 3453 if (!flow) { 3454 if (tunnel_ops->enabled) 3455 port_flow_tunnel_offload_cmd_release(port_id, 3456 tunnel_ops, pft); 3457 free(pf); 3458 return port_flow_complain(&error); 3459 } 3460 pf->next = port->flow_list; 3461 pf->id = id; 3462 pf->flow = flow; 3463 port->flow_list = pf; 3464 if (tunnel_ops->enabled) 3465 port_flow_tunnel_offload_cmd_release(port_id, tunnel_ops, pft); 3466 printf("Flow rule #%u created\n", pf->id); 3467 return 0; 3468 } 3469 3470 /** Destroy a number of flow rules. */ 3471 int 3472 port_flow_destroy(portid_t port_id, uint32_t n, const uint32_t *rule) 3473 { 3474 struct rte_port *port; 3475 struct port_flow **tmp; 3476 int ret = 0; 3477 3478 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3479 port_id == (portid_t)RTE_PORT_ALL) 3480 return -EINVAL; 3481 port = &ports[port_id]; 3482 tmp = &port->flow_list; 3483 while (*tmp) { 3484 uint32_t i; 3485 3486 for (i = 0; i != n; ++i) { 3487 struct rte_flow_error error; 3488 struct port_flow *pf = *tmp; 3489 3490 if (rule[i] != pf->id) 3491 continue; 3492 /* 3493 * Poisoning to make sure PMDs update it in case 3494 * of error. 3495 */ 3496 memset(&error, 0x33, sizeof(error)); 3497 if (rte_flow_destroy(port_id, pf->flow, &error)) { 3498 ret = port_flow_complain(&error); 3499 continue; 3500 } 3501 printf("Flow rule #%u destroyed\n", pf->id); 3502 *tmp = pf->next; 3503 free(pf); 3504 break; 3505 } 3506 if (i == n) 3507 tmp = &(*tmp)->next; 3508 } 3509 return ret; 3510 } 3511 3512 /** Remove all flow rules. */ 3513 int 3514 port_flow_flush(portid_t port_id) 3515 { 3516 struct rte_flow_error error; 3517 struct rte_port *port; 3518 int ret = 0; 3519 3520 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3521 port_id == (portid_t)RTE_PORT_ALL) 3522 return -EINVAL; 3523 3524 port = &ports[port_id]; 3525 3526 if (port->flow_list == NULL) 3527 return ret; 3528 3529 /* Poisoning to make sure PMDs update it in case of error. */ 3530 memset(&error, 0x44, sizeof(error)); 3531 if (rte_flow_flush(port_id, &error)) { 3532 port_flow_complain(&error); 3533 } 3534 3535 while (port->flow_list) { 3536 struct port_flow *pf = port->flow_list->next; 3537 3538 free(port->flow_list); 3539 port->flow_list = pf; 3540 } 3541 return ret; 3542 } 3543 3544 /** Dump flow rules. */ 3545 int 3546 port_flow_dump(portid_t port_id, bool dump_all, uint32_t rule_id, 3547 const char *file_name) 3548 { 3549 int ret = 0; 3550 FILE *file = stdout; 3551 struct rte_flow_error error; 3552 struct rte_port *port; 3553 struct port_flow *pflow; 3554 struct rte_flow *tmpFlow = NULL; 3555 bool found = false; 3556 3557 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3558 port_id == (portid_t)RTE_PORT_ALL) 3559 return -EINVAL; 3560 3561 if (!dump_all) { 3562 port = &ports[port_id]; 3563 pflow = port->flow_list; 3564 while (pflow) { 3565 if (rule_id != pflow->id) { 3566 pflow = pflow->next; 3567 } else { 3568 tmpFlow = pflow->flow; 3569 if (tmpFlow) 3570 found = true; 3571 break; 3572 } 3573 } 3574 if (found == false) { 3575 fprintf(stderr, "Failed to dump to flow %d\n", rule_id); 3576 return -EINVAL; 3577 } 3578 } 3579 3580 if (file_name && strlen(file_name)) { 3581 file = fopen(file_name, "w"); 3582 if (!file) { 3583 fprintf(stderr, "Failed to create file %s: %s\n", 3584 file_name, strerror(errno)); 3585 return -errno; 3586 } 3587 } 3588 3589 if (!dump_all) 3590 ret = rte_flow_dev_dump(port_id, tmpFlow, file, &error); 3591 else 3592 ret = rte_flow_dev_dump(port_id, NULL, file, &error); 3593 if (ret) { 3594 port_flow_complain(&error); 3595 fprintf(stderr, "Failed to dump flow: %s\n", strerror(-ret)); 3596 } else 3597 printf("Flow dump finished\n"); 3598 if (file_name && strlen(file_name)) 3599 fclose(file); 3600 return ret; 3601 } 3602 3603 /** Query a flow rule. */ 3604 int 3605 port_flow_query(portid_t port_id, uint32_t rule, 3606 const struct rte_flow_action *action) 3607 { 3608 struct rte_flow_error error; 3609 struct rte_port *port; 3610 struct port_flow *pf; 3611 const char *name; 3612 union { 3613 struct rte_flow_query_count count; 3614 struct rte_flow_action_rss rss_conf; 3615 struct rte_flow_query_age age; 3616 } query; 3617 int ret; 3618 3619 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3620 port_id == (portid_t)RTE_PORT_ALL) 3621 return -EINVAL; 3622 port = &ports[port_id]; 3623 for (pf = port->flow_list; pf; pf = pf->next) 3624 if (pf->id == rule) 3625 break; 3626 if (!pf) { 3627 fprintf(stderr, "Flow rule #%u not found\n", rule); 3628 return -ENOENT; 3629 } 3630 ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, 3631 &name, sizeof(name), 3632 (void *)(uintptr_t)action->type, &error); 3633 if (ret < 0) 3634 return port_flow_complain(&error); 3635 switch (action->type) { 3636 case RTE_FLOW_ACTION_TYPE_COUNT: 3637 case RTE_FLOW_ACTION_TYPE_RSS: 3638 case RTE_FLOW_ACTION_TYPE_AGE: 3639 break; 3640 default: 3641 fprintf(stderr, "Cannot query action type %d (%s)\n", 3642 action->type, name); 3643 return -ENOTSUP; 3644 } 3645 /* Poisoning to make sure PMDs update it in case of error. */ 3646 memset(&error, 0x55, sizeof(error)); 3647 memset(&query, 0, sizeof(query)); 3648 if (rte_flow_query(port_id, pf->flow, action, &query, &error)) 3649 return port_flow_complain(&error); 3650 switch (action->type) { 3651 case RTE_FLOW_ACTION_TYPE_COUNT: 3652 printf("%s:\n" 3653 " hits_set: %u\n" 3654 " bytes_set: %u\n" 3655 " hits: %" PRIu64 "\n" 3656 " bytes: %" PRIu64 "\n", 3657 name, 3658 query.count.hits_set, 3659 query.count.bytes_set, 3660 query.count.hits, 3661 query.count.bytes); 3662 break; 3663 case RTE_FLOW_ACTION_TYPE_RSS: 3664 rss_config_display(&query.rss_conf); 3665 break; 3666 case RTE_FLOW_ACTION_TYPE_AGE: 3667 printf("%s:\n" 3668 " aged: %u\n" 3669 " sec_since_last_hit_valid: %u\n" 3670 " sec_since_last_hit: %" PRIu32 "\n", 3671 name, 3672 query.age.aged, 3673 query.age.sec_since_last_hit_valid, 3674 query.age.sec_since_last_hit); 3675 break; 3676 default: 3677 fprintf(stderr, 3678 "Cannot display result for action type %d (%s)\n", 3679 action->type, name); 3680 break; 3681 } 3682 return 0; 3683 } 3684 3685 /** List simply and destroy all aged flows. */ 3686 void 3687 port_flow_aged(portid_t port_id, uint8_t destroy) 3688 { 3689 void **contexts; 3690 int nb_context, total = 0, idx; 3691 struct rte_flow_error error; 3692 enum age_action_context_type *type; 3693 union { 3694 struct port_flow *pf; 3695 struct port_indirect_action *pia; 3696 } ctx; 3697 3698 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3699 port_id == (portid_t)RTE_PORT_ALL) 3700 return; 3701 total = rte_flow_get_aged_flows(port_id, NULL, 0, &error); 3702 printf("Port %u total aged flows: %d\n", port_id, total); 3703 if (total < 0) { 3704 port_flow_complain(&error); 3705 return; 3706 } 3707 if (total == 0) 3708 return; 3709 contexts = malloc(sizeof(void *) * total); 3710 if (contexts == NULL) { 3711 fprintf(stderr, "Cannot allocate contexts for aged flow\n"); 3712 return; 3713 } 3714 printf("%-20s\tID\tGroup\tPrio\tAttr\n", "Type"); 3715 nb_context = rte_flow_get_aged_flows(port_id, contexts, total, &error); 3716 if (nb_context != total) { 3717 fprintf(stderr, 3718 "Port:%d get aged flows count(%d) != total(%d)\n", 3719 port_id, nb_context, total); 3720 free(contexts); 3721 return; 3722 } 3723 total = 0; 3724 for (idx = 0; idx < nb_context; idx++) { 3725 if (!contexts[idx]) { 3726 fprintf(stderr, "Error: get Null context in port %u\n", 3727 port_id); 3728 continue; 3729 } 3730 type = (enum age_action_context_type *)contexts[idx]; 3731 switch (*type) { 3732 case ACTION_AGE_CONTEXT_TYPE_FLOW: 3733 ctx.pf = container_of(type, struct port_flow, age_type); 3734 printf("%-20s\t%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 3735 "\t%c%c%c\t\n", 3736 "Flow", 3737 ctx.pf->id, 3738 ctx.pf->rule.attr->group, 3739 ctx.pf->rule.attr->priority, 3740 ctx.pf->rule.attr->ingress ? 'i' : '-', 3741 ctx.pf->rule.attr->egress ? 'e' : '-', 3742 ctx.pf->rule.attr->transfer ? 't' : '-'); 3743 if (destroy && !port_flow_destroy(port_id, 1, 3744 &ctx.pf->id)) 3745 total++; 3746 break; 3747 case ACTION_AGE_CONTEXT_TYPE_INDIRECT_ACTION: 3748 ctx.pia = container_of(type, 3749 struct port_indirect_action, age_type); 3750 printf("%-20s\t%" PRIu32 "\n", "Indirect action", 3751 ctx.pia->id); 3752 break; 3753 default: 3754 fprintf(stderr, "Error: invalid context type %u\n", 3755 port_id); 3756 break; 3757 } 3758 } 3759 printf("\n%d flows destroyed\n", total); 3760 free(contexts); 3761 } 3762 3763 /** List flow rules. */ 3764 void 3765 port_flow_list(portid_t port_id, uint32_t n, const uint32_t *group) 3766 { 3767 struct rte_port *port; 3768 struct port_flow *pf; 3769 struct port_flow *list = NULL; 3770 uint32_t i; 3771 3772 if (port_id_is_invalid(port_id, ENABLED_WARN) || 3773 port_id == (portid_t)RTE_PORT_ALL) 3774 return; 3775 port = &ports[port_id]; 3776 if (!port->flow_list) 3777 return; 3778 /* Sort flows by group, priority and ID. */ 3779 for (pf = port->flow_list; pf != NULL; pf = pf->next) { 3780 struct port_flow **tmp; 3781 const struct rte_flow_attr *curr = pf->rule.attr; 3782 3783 if (n) { 3784 /* Filter out unwanted groups. */ 3785 for (i = 0; i != n; ++i) 3786 if (curr->group == group[i]) 3787 break; 3788 if (i == n) 3789 continue; 3790 } 3791 for (tmp = &list; *tmp; tmp = &(*tmp)->tmp) { 3792 const struct rte_flow_attr *comp = (*tmp)->rule.attr; 3793 3794 if (curr->group > comp->group || 3795 (curr->group == comp->group && 3796 curr->priority > comp->priority) || 3797 (curr->group == comp->group && 3798 curr->priority == comp->priority && 3799 pf->id > (*tmp)->id)) 3800 continue; 3801 break; 3802 } 3803 pf->tmp = *tmp; 3804 *tmp = pf; 3805 } 3806 printf("ID\tGroup\tPrio\tAttr\tRule\n"); 3807 for (pf = list; pf != NULL; pf = pf->tmp) { 3808 const struct rte_flow_item *item = pf->rule.pattern; 3809 const struct rte_flow_action *action = pf->rule.actions; 3810 const char *name; 3811 3812 printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t", 3813 pf->id, 3814 pf->rule.attr->group, 3815 pf->rule.attr->priority, 3816 pf->rule.attr->ingress ? 'i' : '-', 3817 pf->rule.attr->egress ? 'e' : '-', 3818 pf->rule.attr->transfer ? 't' : '-'); 3819 while (item->type != RTE_FLOW_ITEM_TYPE_END) { 3820 if ((uint32_t)item->type > INT_MAX) 3821 name = "PMD_INTERNAL"; 3822 else if (rte_flow_conv(RTE_FLOW_CONV_OP_ITEM_NAME_PTR, 3823 &name, sizeof(name), 3824 (void *)(uintptr_t)item->type, 3825 NULL) <= 0) 3826 name = "[UNKNOWN]"; 3827 if (item->type != RTE_FLOW_ITEM_TYPE_VOID) 3828 printf("%s ", name); 3829 ++item; 3830 } 3831 printf("=>"); 3832 while (action->type != RTE_FLOW_ACTION_TYPE_END) { 3833 if ((uint32_t)action->type > INT_MAX) 3834 name = "PMD_INTERNAL"; 3835 else if (rte_flow_conv(RTE_FLOW_CONV_OP_ACTION_NAME_PTR, 3836 &name, sizeof(name), 3837 (void *)(uintptr_t)action->type, 3838 NULL) <= 0) 3839 name = "[UNKNOWN]"; 3840 if (action->type != RTE_FLOW_ACTION_TYPE_VOID) 3841 printf(" %s", name); 3842 ++action; 3843 } 3844 printf("\n"); 3845 } 3846 } 3847 3848 /** Restrict ingress traffic to the defined flow rules. */ 3849 int 3850 port_flow_isolate(portid_t port_id, int set) 3851 { 3852 struct rte_flow_error error; 3853 3854 /* Poisoning to make sure PMDs update it in case of error. */ 3855 memset(&error, 0x66, sizeof(error)); 3856 if (rte_flow_isolate(port_id, set, &error)) 3857 return port_flow_complain(&error); 3858 printf("Ingress traffic on port %u is %s to the defined flow rules\n", 3859 port_id, 3860 set ? "now restricted" : "not restricted anymore"); 3861 return 0; 3862 } 3863 3864 /* 3865 * RX/TX ring descriptors display functions. 3866 */ 3867 int 3868 rx_queue_id_is_invalid(queueid_t rxq_id) 3869 { 3870 if (rxq_id < nb_rxq) 3871 return 0; 3872 fprintf(stderr, "Invalid RX queue %d (must be < nb_rxq=%d)\n", 3873 rxq_id, nb_rxq); 3874 return 1; 3875 } 3876 3877 int 3878 tx_queue_id_is_invalid(queueid_t txq_id) 3879 { 3880 if (txq_id < nb_txq) 3881 return 0; 3882 fprintf(stderr, "Invalid TX queue %d (must be < nb_txq=%d)\n", 3883 txq_id, nb_txq); 3884 return 1; 3885 } 3886 3887 static int 3888 get_rx_ring_size(portid_t port_id, queueid_t rxq_id, uint16_t *ring_size) 3889 { 3890 struct rte_port *port = &ports[port_id]; 3891 struct rte_eth_rxq_info rx_qinfo; 3892 int ret; 3893 3894 ret = rte_eth_rx_queue_info_get(port_id, rxq_id, &rx_qinfo); 3895 if (ret == 0) { 3896 *ring_size = rx_qinfo.nb_desc; 3897 return ret; 3898 } 3899 3900 if (ret != -ENOTSUP) 3901 return ret; 3902 /* 3903 * If the rte_eth_rx_queue_info_get is not support for this PMD, 3904 * ring_size stored in testpmd will be used for validity verification. 3905 * When configure the rxq by rte_eth_rx_queue_setup with nb_rx_desc 3906 * being 0, it will use a default value provided by PMDs to setup this 3907 * rxq. If the default value is 0, it will use the 3908 * RTE_ETH_DEV_FALLBACK_RX_RINGSIZE to setup this rxq. 3909 */ 3910 if (port->nb_rx_desc[rxq_id]) 3911 *ring_size = port->nb_rx_desc[rxq_id]; 3912 else if (port->dev_info.default_rxportconf.ring_size) 3913 *ring_size = port->dev_info.default_rxportconf.ring_size; 3914 else 3915 *ring_size = RTE_ETH_DEV_FALLBACK_RX_RINGSIZE; 3916 return 0; 3917 } 3918 3919 static int 3920 get_tx_ring_size(portid_t port_id, queueid_t txq_id, uint16_t *ring_size) 3921 { 3922 struct rte_port *port = &ports[port_id]; 3923 struct rte_eth_txq_info tx_qinfo; 3924 int ret; 3925 3926 ret = rte_eth_tx_queue_info_get(port_id, txq_id, &tx_qinfo); 3927 if (ret == 0) { 3928 *ring_size = tx_qinfo.nb_desc; 3929 return ret; 3930 } 3931 3932 if (ret != -ENOTSUP) 3933 return ret; 3934 /* 3935 * If the rte_eth_tx_queue_info_get is not support for this PMD, 3936 * ring_size stored in testpmd will be used for validity verification. 3937 * When configure the txq by rte_eth_tx_queue_setup with nb_tx_desc 3938 * being 0, it will use a default value provided by PMDs to setup this 3939 * txq. If the default value is 0, it will use the 3940 * RTE_ETH_DEV_FALLBACK_TX_RINGSIZE to setup this txq. 3941 */ 3942 if (port->nb_tx_desc[txq_id]) 3943 *ring_size = port->nb_tx_desc[txq_id]; 3944 else if (port->dev_info.default_txportconf.ring_size) 3945 *ring_size = port->dev_info.default_txportconf.ring_size; 3946 else 3947 *ring_size = RTE_ETH_DEV_FALLBACK_TX_RINGSIZE; 3948 return 0; 3949 } 3950 3951 static int 3952 rx_desc_id_is_invalid(portid_t port_id, queueid_t rxq_id, uint16_t rxdesc_id) 3953 { 3954 uint16_t ring_size; 3955 int ret; 3956 3957 ret = get_rx_ring_size(port_id, rxq_id, &ring_size); 3958 if (ret) 3959 return 1; 3960 3961 if (rxdesc_id < ring_size) 3962 return 0; 3963 3964 fprintf(stderr, "Invalid RX descriptor %u (must be < ring_size=%u)\n", 3965 rxdesc_id, ring_size); 3966 return 1; 3967 } 3968 3969 static int 3970 tx_desc_id_is_invalid(portid_t port_id, queueid_t txq_id, uint16_t txdesc_id) 3971 { 3972 uint16_t ring_size; 3973 int ret; 3974 3975 ret = get_tx_ring_size(port_id, txq_id, &ring_size); 3976 if (ret) 3977 return 1; 3978 3979 if (txdesc_id < ring_size) 3980 return 0; 3981 3982 fprintf(stderr, "Invalid TX descriptor %u (must be < ring_size=%u)\n", 3983 txdesc_id, ring_size); 3984 return 1; 3985 } 3986 3987 static const struct rte_memzone * 3988 ring_dma_zone_lookup(const char *ring_name, portid_t port_id, uint16_t q_id) 3989 { 3990 char mz_name[RTE_MEMZONE_NAMESIZE]; 3991 const struct rte_memzone *mz; 3992 3993 snprintf(mz_name, sizeof(mz_name), "eth_p%d_q%d_%s", 3994 port_id, q_id, ring_name); 3995 mz = rte_memzone_lookup(mz_name); 3996 if (mz == NULL) 3997 fprintf(stderr, 3998 "%s ring memory zoneof (port %d, queue %d) not found (zone name = %s\n", 3999 ring_name, port_id, q_id, mz_name); 4000 return mz; 4001 } 4002 4003 union igb_ring_dword { 4004 uint64_t dword; 4005 struct { 4006 #if RTE_BYTE_ORDER == RTE_BIG_ENDIAN 4007 uint32_t lo; 4008 uint32_t hi; 4009 #else 4010 uint32_t hi; 4011 uint32_t lo; 4012 #endif 4013 } words; 4014 }; 4015 4016 struct igb_ring_desc_32_bytes { 4017 union igb_ring_dword lo_dword; 4018 union igb_ring_dword hi_dword; 4019 union igb_ring_dword resv1; 4020 union igb_ring_dword resv2; 4021 }; 4022 4023 struct igb_ring_desc_16_bytes { 4024 union igb_ring_dword lo_dword; 4025 union igb_ring_dword hi_dword; 4026 }; 4027 4028 static void 4029 ring_rxd_display_dword(union igb_ring_dword dword) 4030 { 4031 printf(" 0x%08X - 0x%08X\n", (unsigned)dword.words.lo, 4032 (unsigned)dword.words.hi); 4033 } 4034 4035 static void 4036 ring_rx_descriptor_display(const struct rte_memzone *ring_mz, 4037 #ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC 4038 portid_t port_id, 4039 #else 4040 __rte_unused portid_t port_id, 4041 #endif 4042 uint16_t desc_id) 4043 { 4044 struct igb_ring_desc_16_bytes *ring = 4045 (struct igb_ring_desc_16_bytes *)ring_mz->addr; 4046 #ifndef RTE_LIBRTE_I40E_16BYTE_RX_DESC 4047 int ret; 4048 struct rte_eth_dev_info dev_info; 4049 4050 ret = eth_dev_info_get_print_err(port_id, &dev_info); 4051 if (ret != 0) 4052 return; 4053 4054 if (strstr(dev_info.driver_name, "i40e") != NULL) { 4055 /* 32 bytes RX descriptor, i40e only */ 4056 struct igb_ring_desc_32_bytes *ring = 4057 (struct igb_ring_desc_32_bytes *)ring_mz->addr; 4058 ring[desc_id].lo_dword.dword = 4059 rte_le_to_cpu_64(ring[desc_id].lo_dword.dword); 4060 ring_rxd_display_dword(ring[desc_id].lo_dword); 4061 ring[desc_id].hi_dword.dword = 4062 rte_le_to_cpu_64(ring[desc_id].hi_dword.dword); 4063 ring_rxd_display_dword(ring[desc_id].hi_dword); 4064 ring[desc_id].resv1.dword = 4065 rte_le_to_cpu_64(ring[desc_id].resv1.dword); 4066 ring_rxd_display_dword(ring[desc_id].resv1); 4067 ring[desc_id].resv2.dword = 4068 rte_le_to_cpu_64(ring[desc_id].resv2.dword); 4069 ring_rxd_display_dword(ring[desc_id].resv2); 4070 4071 return; 4072 } 4073 #endif 4074 /* 16 bytes RX descriptor */ 4075 ring[desc_id].lo_dword.dword = 4076 rte_le_to_cpu_64(ring[desc_id].lo_dword.dword); 4077 ring_rxd_display_dword(ring[desc_id].lo_dword); 4078 ring[desc_id].hi_dword.dword = 4079 rte_le_to_cpu_64(ring[desc_id].hi_dword.dword); 4080 ring_rxd_display_dword(ring[desc_id].hi_dword); 4081 } 4082 4083 static void 4084 ring_tx_descriptor_display(const struct rte_memzone *ring_mz, uint16_t desc_id) 4085 { 4086 struct igb_ring_desc_16_bytes *ring; 4087 struct igb_ring_desc_16_bytes txd; 4088 4089 ring = (struct igb_ring_desc_16_bytes *)ring_mz->addr; 4090 txd.lo_dword.dword = rte_le_to_cpu_64(ring[desc_id].lo_dword.dword); 4091 txd.hi_dword.dword = rte_le_to_cpu_64(ring[desc_id].hi_dword.dword); 4092 printf(" 0x%08X - 0x%08X / 0x%08X - 0x%08X\n", 4093 (unsigned)txd.lo_dword.words.lo, 4094 (unsigned)txd.lo_dword.words.hi, 4095 (unsigned)txd.hi_dword.words.lo, 4096 (unsigned)txd.hi_dword.words.hi); 4097 } 4098 4099 void 4100 rx_ring_desc_display(portid_t port_id, queueid_t rxq_id, uint16_t rxd_id) 4101 { 4102 const struct rte_memzone *rx_mz; 4103 4104 if (rx_desc_id_is_invalid(port_id, rxq_id, rxd_id)) 4105 return; 4106 rx_mz = ring_dma_zone_lookup("rx_ring", port_id, rxq_id); 4107 if (rx_mz == NULL) 4108 return; 4109 ring_rx_descriptor_display(rx_mz, port_id, rxd_id); 4110 } 4111 4112 void 4113 tx_ring_desc_display(portid_t port_id, queueid_t txq_id, uint16_t txd_id) 4114 { 4115 const struct rte_memzone *tx_mz; 4116 4117 if (tx_desc_id_is_invalid(port_id, txq_id, txd_id)) 4118 return; 4119 tx_mz = ring_dma_zone_lookup("tx_ring", port_id, txq_id); 4120 if (tx_mz == NULL) 4121 return; 4122 ring_tx_descriptor_display(tx_mz, txd_id); 4123 } 4124 4125 void 4126 fwd_lcores_config_display(void) 4127 { 4128 lcoreid_t lc_id; 4129 4130 printf("List of forwarding lcores:"); 4131 for (lc_id = 0; lc_id < nb_cfg_lcores; lc_id++) 4132 printf(" %2u", fwd_lcores_cpuids[lc_id]); 4133 printf("\n"); 4134 } 4135 void 4136 rxtx_config_display(void) 4137 { 4138 portid_t pid; 4139 queueid_t qid; 4140 4141 printf(" %s packet forwarding%s packets/burst=%d\n", 4142 cur_fwd_eng->fwd_mode_name, 4143 retry_enabled == 0 ? "" : " with retry", 4144 nb_pkt_per_burst); 4145 4146 if (cur_fwd_eng == &tx_only_engine || cur_fwd_eng == &flow_gen_engine) 4147 printf(" packet len=%u - nb packet segments=%d\n", 4148 (unsigned)tx_pkt_length, (int) tx_pkt_nb_segs); 4149 4150 printf(" nb forwarding cores=%d - nb forwarding ports=%d\n", 4151 nb_fwd_lcores, nb_fwd_ports); 4152 4153 RTE_ETH_FOREACH_DEV(pid) { 4154 struct rte_eth_rxconf *rx_conf = &ports[pid].rxq[0].conf; 4155 struct rte_eth_txconf *tx_conf = &ports[pid].txq[0].conf; 4156 uint16_t *nb_rx_desc = &ports[pid].nb_rx_desc[0]; 4157 uint16_t *nb_tx_desc = &ports[pid].nb_tx_desc[0]; 4158 struct rte_eth_rxq_info rx_qinfo; 4159 struct rte_eth_txq_info tx_qinfo; 4160 uint16_t rx_free_thresh_tmp; 4161 uint16_t tx_free_thresh_tmp; 4162 uint16_t tx_rs_thresh_tmp; 4163 uint16_t nb_rx_desc_tmp; 4164 uint16_t nb_tx_desc_tmp; 4165 uint64_t offloads_tmp; 4166 uint8_t pthresh_tmp; 4167 uint8_t hthresh_tmp; 4168 uint8_t wthresh_tmp; 4169 int32_t rc; 4170 4171 /* per port config */ 4172 printf(" port %d: RX queue number: %d Tx queue number: %d\n", 4173 (unsigned int)pid, nb_rxq, nb_txq); 4174 4175 printf(" Rx offloads=0x%"PRIx64" Tx offloads=0x%"PRIx64"\n", 4176 ports[pid].dev_conf.rxmode.offloads, 4177 ports[pid].dev_conf.txmode.offloads); 4178 4179 /* per rx queue config only for first queue to be less verbose */ 4180 for (qid = 0; qid < 1; qid++) { 4181 rc = rte_eth_rx_queue_info_get(pid, qid, &rx_qinfo); 4182 if (rc) { 4183 nb_rx_desc_tmp = nb_rx_desc[qid]; 4184 rx_free_thresh_tmp = 4185 rx_conf[qid].rx_free_thresh; 4186 pthresh_tmp = rx_conf[qid].rx_thresh.pthresh; 4187 hthresh_tmp = rx_conf[qid].rx_thresh.hthresh; 4188 wthresh_tmp = rx_conf[qid].rx_thresh.wthresh; 4189 offloads_tmp = rx_conf[qid].offloads; 4190 } else { 4191 nb_rx_desc_tmp = rx_qinfo.nb_desc; 4192 rx_free_thresh_tmp = 4193 rx_qinfo.conf.rx_free_thresh; 4194 pthresh_tmp = rx_qinfo.conf.rx_thresh.pthresh; 4195 hthresh_tmp = rx_qinfo.conf.rx_thresh.hthresh; 4196 wthresh_tmp = rx_qinfo.conf.rx_thresh.wthresh; 4197 offloads_tmp = rx_qinfo.conf.offloads; 4198 } 4199 4200 printf(" RX queue: %d\n", qid); 4201 printf(" RX desc=%d - RX free threshold=%d\n", 4202 nb_rx_desc_tmp, rx_free_thresh_tmp); 4203 printf(" RX threshold registers: pthresh=%d hthresh=%d " 4204 " wthresh=%d\n", 4205 pthresh_tmp, hthresh_tmp, wthresh_tmp); 4206 printf(" RX Offloads=0x%"PRIx64, offloads_tmp); 4207 if (rx_conf->share_group > 0) 4208 printf(" share_group=%u share_qid=%u", 4209 rx_conf->share_group, 4210 rx_conf->share_qid); 4211 printf("\n"); 4212 } 4213 4214 /* per tx queue config only for first queue to be less verbose */ 4215 for (qid = 0; qid < 1; qid++) { 4216 rc = rte_eth_tx_queue_info_get(pid, qid, &tx_qinfo); 4217 if (rc) { 4218 nb_tx_desc_tmp = nb_tx_desc[qid]; 4219 tx_free_thresh_tmp = 4220 tx_conf[qid].tx_free_thresh; 4221 pthresh_tmp = tx_conf[qid].tx_thresh.pthresh; 4222 hthresh_tmp = tx_conf[qid].tx_thresh.hthresh; 4223 wthresh_tmp = tx_conf[qid].tx_thresh.wthresh; 4224 offloads_tmp = tx_conf[qid].offloads; 4225 tx_rs_thresh_tmp = tx_conf[qid].tx_rs_thresh; 4226 } else { 4227 nb_tx_desc_tmp = tx_qinfo.nb_desc; 4228 tx_free_thresh_tmp = 4229 tx_qinfo.conf.tx_free_thresh; 4230 pthresh_tmp = tx_qinfo.conf.tx_thresh.pthresh; 4231 hthresh_tmp = tx_qinfo.conf.tx_thresh.hthresh; 4232 wthresh_tmp = tx_qinfo.conf.tx_thresh.wthresh; 4233 offloads_tmp = tx_qinfo.conf.offloads; 4234 tx_rs_thresh_tmp = tx_qinfo.conf.tx_rs_thresh; 4235 } 4236 4237 printf(" TX queue: %d\n", qid); 4238 printf(" TX desc=%d - TX free threshold=%d\n", 4239 nb_tx_desc_tmp, tx_free_thresh_tmp); 4240 printf(" TX threshold registers: pthresh=%d hthresh=%d " 4241 " wthresh=%d\n", 4242 pthresh_tmp, hthresh_tmp, wthresh_tmp); 4243 printf(" TX offloads=0x%"PRIx64" - TX RS bit threshold=%d\n", 4244 offloads_tmp, tx_rs_thresh_tmp); 4245 } 4246 } 4247 } 4248 4249 void 4250 port_rss_reta_info(portid_t port_id, 4251 struct rte_eth_rss_reta_entry64 *reta_conf, 4252 uint16_t nb_entries) 4253 { 4254 uint16_t i, idx, shift; 4255 int ret; 4256 4257 if (port_id_is_invalid(port_id, ENABLED_WARN)) 4258 return; 4259 4260 ret = rte_eth_dev_rss_reta_query(port_id, reta_conf, nb_entries); 4261 if (ret != 0) { 4262 fprintf(stderr, 4263 "Failed to get RSS RETA info, return code = %d\n", 4264 ret); 4265 return; 4266 } 4267 4268 for (i = 0; i < nb_entries; i++) { 4269 idx = i / RTE_ETH_RETA_GROUP_SIZE; 4270 shift = i % RTE_ETH_RETA_GROUP_SIZE; 4271 if (!(reta_conf[idx].mask & (1ULL << shift))) 4272 continue; 4273 printf("RSS RETA configuration: hash index=%u, queue=%u\n", 4274 i, reta_conf[idx].reta[shift]); 4275 } 4276 } 4277 4278 /* 4279 * Displays the RSS hash functions of a port, and, optionally, the RSS hash 4280 * key of the port. 4281 */ 4282 void 4283 port_rss_hash_conf_show(portid_t port_id, int show_rss_key) 4284 { 4285 struct rte_eth_rss_conf rss_conf = {0}; 4286 uint8_t rss_key[RSS_HASH_KEY_LENGTH]; 4287 uint64_t rss_hf; 4288 uint8_t i; 4289 int diag; 4290 struct rte_eth_dev_info dev_info; 4291 uint8_t hash_key_size; 4292 int ret; 4293 4294 if (port_id_is_invalid(port_id, ENABLED_WARN)) 4295 return; 4296 4297 ret = eth_dev_info_get_print_err(port_id, &dev_info); 4298 if (ret != 0) 4299 return; 4300 4301 if (dev_info.hash_key_size > 0 && 4302 dev_info.hash_key_size <= sizeof(rss_key)) 4303 hash_key_size = dev_info.hash_key_size; 4304 else { 4305 fprintf(stderr, 4306 "dev_info did not provide a valid hash key size\n"); 4307 return; 4308 } 4309 4310 /* Get RSS hash key if asked to display it */ 4311 rss_conf.rss_key = (show_rss_key) ? rss_key : NULL; 4312 rss_conf.rss_key_len = hash_key_size; 4313 diag = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf); 4314 if (diag != 0) { 4315 switch (diag) { 4316 case -ENODEV: 4317 fprintf(stderr, "port index %d invalid\n", port_id); 4318 break; 4319 case -ENOTSUP: 4320 fprintf(stderr, "operation not supported by device\n"); 4321 break; 4322 default: 4323 fprintf(stderr, "operation failed - diag=%d\n", diag); 4324 break; 4325 } 4326 return; 4327 } 4328 rss_hf = rss_conf.rss_hf; 4329 if (rss_hf == 0) { 4330 printf("RSS disabled\n"); 4331 return; 4332 } 4333 printf("RSS functions:\n"); 4334 rss_types_display(rss_hf, TESTPMD_RSS_TYPES_CHAR_NUM_PER_LINE); 4335 if (!show_rss_key) 4336 return; 4337 printf("RSS key:\n"); 4338 for (i = 0; i < hash_key_size; i++) 4339 printf("%02X", rss_key[i]); 4340 printf("\n"); 4341 } 4342 4343 void 4344 port_rss_hash_key_update(portid_t port_id, char rss_type[], uint8_t *hash_key, 4345 uint8_t hash_key_len) 4346 { 4347 struct rte_eth_rss_conf rss_conf; 4348 int diag; 4349 4350 rss_conf.rss_key = NULL; 4351 rss_conf.rss_key_len = 0; 4352 rss_conf.rss_hf = str_to_rsstypes(rss_type); 4353 diag = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf); 4354 if (diag == 0) { 4355 rss_conf.rss_key = hash_key; 4356 rss_conf.rss_key_len = hash_key_len; 4357 diag = rte_eth_dev_rss_hash_update(port_id, &rss_conf); 4358 } 4359 if (diag == 0) 4360 return; 4361 4362 switch (diag) { 4363 case -ENODEV: 4364 fprintf(stderr, "port index %d invalid\n", port_id); 4365 break; 4366 case -ENOTSUP: 4367 fprintf(stderr, "operation not supported by device\n"); 4368 break; 4369 default: 4370 fprintf(stderr, "operation failed - diag=%d\n", diag); 4371 break; 4372 } 4373 } 4374 4375 /* 4376 * Check whether a shared rxq scheduled on other lcores. 4377 */ 4378 static bool 4379 fwd_stream_on_other_lcores(uint16_t domain_id, lcoreid_t src_lc, 4380 portid_t src_port, queueid_t src_rxq, 4381 uint32_t share_group, queueid_t share_rxq) 4382 { 4383 streamid_t sm_id; 4384 streamid_t nb_fs_per_lcore; 4385 lcoreid_t nb_fc; 4386 lcoreid_t lc_id; 4387 struct fwd_stream *fs; 4388 struct rte_port *port; 4389 struct rte_eth_dev_info *dev_info; 4390 struct rte_eth_rxconf *rxq_conf; 4391 4392 nb_fc = cur_fwd_config.nb_fwd_lcores; 4393 /* Check remaining cores. */ 4394 for (lc_id = src_lc + 1; lc_id < nb_fc; lc_id++) { 4395 sm_id = fwd_lcores[lc_id]->stream_idx; 4396 nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb; 4397 for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore; 4398 sm_id++) { 4399 fs = fwd_streams[sm_id]; 4400 port = &ports[fs->rx_port]; 4401 dev_info = &port->dev_info; 4402 rxq_conf = &port->rxq[fs->rx_queue].conf; 4403 if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) 4404 == 0 || rxq_conf->share_group == 0) 4405 /* Not shared rxq. */ 4406 continue; 4407 if (domain_id != port->dev_info.switch_info.domain_id) 4408 continue; 4409 if (rxq_conf->share_group != share_group) 4410 continue; 4411 if (rxq_conf->share_qid != share_rxq) 4412 continue; 4413 printf("Shared Rx queue group %u queue %hu can't be scheduled on different cores:\n", 4414 share_group, share_rxq); 4415 printf(" lcore %hhu Port %hu queue %hu\n", 4416 src_lc, src_port, src_rxq); 4417 printf(" lcore %hhu Port %hu queue %hu\n", 4418 lc_id, fs->rx_port, fs->rx_queue); 4419 printf("Please use --nb-cores=%hu to limit number of forwarding cores\n", 4420 nb_rxq); 4421 return true; 4422 } 4423 } 4424 return false; 4425 } 4426 4427 /* 4428 * Check shared rxq configuration. 4429 * 4430 * Shared group must not being scheduled on different core. 4431 */ 4432 bool 4433 pkt_fwd_shared_rxq_check(void) 4434 { 4435 streamid_t sm_id; 4436 streamid_t nb_fs_per_lcore; 4437 lcoreid_t nb_fc; 4438 lcoreid_t lc_id; 4439 struct fwd_stream *fs; 4440 uint16_t domain_id; 4441 struct rte_port *port; 4442 struct rte_eth_dev_info *dev_info; 4443 struct rte_eth_rxconf *rxq_conf; 4444 4445 if (rxq_share == 0) 4446 return true; 4447 nb_fc = cur_fwd_config.nb_fwd_lcores; 4448 /* 4449 * Check streams on each core, make sure the same switch domain + 4450 * group + queue doesn't get scheduled on other cores. 4451 */ 4452 for (lc_id = 0; lc_id < nb_fc; lc_id++) { 4453 sm_id = fwd_lcores[lc_id]->stream_idx; 4454 nb_fs_per_lcore = fwd_lcores[lc_id]->stream_nb; 4455 for (; sm_id < fwd_lcores[lc_id]->stream_idx + nb_fs_per_lcore; 4456 sm_id++) { 4457 fs = fwd_streams[sm_id]; 4458 /* Update lcore info stream being scheduled. */ 4459 fs->lcore = fwd_lcores[lc_id]; 4460 port = &ports[fs->rx_port]; 4461 dev_info = &port->dev_info; 4462 rxq_conf = &port->rxq[fs->rx_queue].conf; 4463 if ((dev_info->dev_capa & RTE_ETH_DEV_CAPA_RXQ_SHARE) 4464 == 0 || rxq_conf->share_group == 0) 4465 /* Not shared rxq. */ 4466 continue; 4467 /* Check shared rxq not scheduled on remaining cores. */ 4468 domain_id = port->dev_info.switch_info.domain_id; 4469 if (fwd_stream_on_other_lcores(domain_id, lc_id, 4470 fs->rx_port, 4471 fs->rx_queue, 4472 rxq_conf->share_group, 4473 rxq_conf->share_qid)) 4474 return false; 4475 } 4476 } 4477 return true; 4478 } 4479 4480 /* 4481 * Setup forwarding configuration for each logical core. 4482 */ 4483 static void 4484 setup_fwd_config_of_each_lcore(struct fwd_config *cfg) 4485 { 4486 streamid_t nb_fs_per_lcore; 4487 streamid_t nb_fs; 4488 streamid_t sm_id; 4489 lcoreid_t nb_extra; 4490 lcoreid_t nb_fc; 4491 lcoreid_t nb_lc; 4492 lcoreid_t lc_id; 4493 4494 nb_fs = cfg->nb_fwd_streams; 4495 nb_fc = cfg->nb_fwd_lcores; 4496 if (nb_fs <= nb_fc) { 4497 nb_fs_per_lcore = 1; 4498 nb_extra = 0; 4499 } else { 4500 nb_fs_per_lcore = (streamid_t) (nb_fs / nb_fc); 4501 nb_extra = (lcoreid_t) (nb_fs % nb_fc); 4502 } 4503 4504 nb_lc = (lcoreid_t) (nb_fc - nb_extra); 4505 sm_id = 0; 4506 for (lc_id = 0; lc_id < nb_lc; lc_id++) { 4507 fwd_lcores[lc_id]->stream_idx = sm_id; 4508 fwd_lcores[lc_id]->stream_nb = nb_fs_per_lcore; 4509 sm_id = (streamid_t) (sm_id + nb_fs_per_lcore); 4510 } 4511 4512 /* 4513 * Assign extra remaining streams, if any. 4514 */ 4515 nb_fs_per_lcore = (streamid_t) (nb_fs_per_lcore + 1); 4516 for (lc_id = 0; lc_id < nb_extra; lc_id++) { 4517 fwd_lcores[nb_lc + lc_id]->stream_idx = sm_id; 4518 fwd_lcores[nb_lc + lc_id]->stream_nb = nb_fs_per_lcore; 4519 sm_id = (streamid_t) (sm_id + nb_fs_per_lcore); 4520 } 4521 } 4522 4523 static portid_t 4524 fwd_topology_tx_port_get(portid_t rxp) 4525 { 4526 static int warning_once = 1; 4527 4528 RTE_ASSERT(rxp < cur_fwd_config.nb_fwd_ports); 4529 4530 switch (port_topology) { 4531 default: 4532 case PORT_TOPOLOGY_PAIRED: 4533 if ((rxp & 0x1) == 0) { 4534 if (rxp + 1 < cur_fwd_config.nb_fwd_ports) 4535 return rxp + 1; 4536 if (warning_once) { 4537 fprintf(stderr, 4538 "\nWarning! port-topology=paired and odd forward ports number, the last port will pair with itself.\n\n"); 4539 warning_once = 0; 4540 } 4541 return rxp; 4542 } 4543 return rxp - 1; 4544 case PORT_TOPOLOGY_CHAINED: 4545 return (rxp + 1) % cur_fwd_config.nb_fwd_ports; 4546 case PORT_TOPOLOGY_LOOP: 4547 return rxp; 4548 } 4549 } 4550 4551 static void 4552 simple_fwd_config_setup(void) 4553 { 4554 portid_t i; 4555 4556 cur_fwd_config.nb_fwd_ports = (portid_t) nb_fwd_ports; 4557 cur_fwd_config.nb_fwd_streams = 4558 (streamid_t) cur_fwd_config.nb_fwd_ports; 4559 4560 /* reinitialize forwarding streams */ 4561 init_fwd_streams(); 4562 4563 /* 4564 * In the simple forwarding test, the number of forwarding cores 4565 * must be lower or equal to the number of forwarding ports. 4566 */ 4567 cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores; 4568 if (cur_fwd_config.nb_fwd_lcores > cur_fwd_config.nb_fwd_ports) 4569 cur_fwd_config.nb_fwd_lcores = 4570 (lcoreid_t) cur_fwd_config.nb_fwd_ports; 4571 setup_fwd_config_of_each_lcore(&cur_fwd_config); 4572 4573 for (i = 0; i < cur_fwd_config.nb_fwd_ports; i++) { 4574 fwd_streams[i]->rx_port = fwd_ports_ids[i]; 4575 fwd_streams[i]->rx_queue = 0; 4576 fwd_streams[i]->tx_port = 4577 fwd_ports_ids[fwd_topology_tx_port_get(i)]; 4578 fwd_streams[i]->tx_queue = 0; 4579 fwd_streams[i]->peer_addr = fwd_streams[i]->tx_port; 4580 fwd_streams[i]->retry_enabled = retry_enabled; 4581 } 4582 } 4583 4584 /** 4585 * For the RSS forwarding test all streams distributed over lcores. Each stream 4586 * being composed of a RX queue to poll on a RX port for input messages, 4587 * associated with a TX queue of a TX port where to send forwarded packets. 4588 */ 4589 static void 4590 rss_fwd_config_setup(void) 4591 { 4592 portid_t rxp; 4593 portid_t txp; 4594 queueid_t rxq; 4595 queueid_t nb_q; 4596 streamid_t sm_id; 4597 int start; 4598 int end; 4599 4600 nb_q = nb_rxq; 4601 if (nb_q > nb_txq) 4602 nb_q = nb_txq; 4603 cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores; 4604 cur_fwd_config.nb_fwd_ports = nb_fwd_ports; 4605 cur_fwd_config.nb_fwd_streams = 4606 (streamid_t) (nb_q * cur_fwd_config.nb_fwd_ports); 4607 4608 if (cur_fwd_config.nb_fwd_streams < cur_fwd_config.nb_fwd_lcores) 4609 cur_fwd_config.nb_fwd_lcores = 4610 (lcoreid_t)cur_fwd_config.nb_fwd_streams; 4611 4612 /* reinitialize forwarding streams */ 4613 init_fwd_streams(); 4614 4615 setup_fwd_config_of_each_lcore(&cur_fwd_config); 4616 4617 if (proc_id > 0 && nb_q % num_procs != 0) 4618 printf("Warning! queue numbers should be multiple of processes, or packet loss will happen.\n"); 4619 4620 /** 4621 * In multi-process, All queues are allocated to different 4622 * processes based on num_procs and proc_id. For example: 4623 * if supports 4 queues(nb_q), 2 processes(num_procs), 4624 * the 0~1 queue for primary process. 4625 * the 2~3 queue for secondary process. 4626 */ 4627 start = proc_id * nb_q / num_procs; 4628 end = start + nb_q / num_procs; 4629 rxp = 0; 4630 rxq = start; 4631 for (sm_id = 0; sm_id < cur_fwd_config.nb_fwd_streams; sm_id++) { 4632 struct fwd_stream *fs; 4633 4634 fs = fwd_streams[sm_id]; 4635 txp = fwd_topology_tx_port_get(rxp); 4636 fs->rx_port = fwd_ports_ids[rxp]; 4637 fs->rx_queue = rxq; 4638 fs->tx_port = fwd_ports_ids[txp]; 4639 fs->tx_queue = rxq; 4640 fs->peer_addr = fs->tx_port; 4641 fs->retry_enabled = retry_enabled; 4642 rxp++; 4643 if (rxp < nb_fwd_ports) 4644 continue; 4645 rxp = 0; 4646 rxq++; 4647 if (rxq >= end) 4648 rxq = start; 4649 } 4650 } 4651 4652 static uint16_t 4653 get_fwd_port_total_tc_num(void) 4654 { 4655 struct rte_eth_dcb_info dcb_info; 4656 uint16_t total_tc_num = 0; 4657 unsigned int i; 4658 4659 for (i = 0; i < nb_fwd_ports; i++) { 4660 (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[i], &dcb_info); 4661 total_tc_num += dcb_info.nb_tcs; 4662 } 4663 4664 return total_tc_num; 4665 } 4666 4667 /** 4668 * For the DCB forwarding test, each core is assigned on each traffic class. 4669 * 4670 * Each core is assigned a multi-stream, each stream being composed of 4671 * a RX queue to poll on a RX port for input messages, associated with 4672 * a TX queue of a TX port where to send forwarded packets. All RX and 4673 * TX queues are mapping to the same traffic class. 4674 * If VMDQ and DCB co-exist, each traffic class on different POOLs share 4675 * the same core 4676 */ 4677 static void 4678 dcb_fwd_config_setup(void) 4679 { 4680 struct rte_eth_dcb_info rxp_dcb_info, txp_dcb_info; 4681 portid_t txp, rxp = 0; 4682 queueid_t txq, rxq = 0; 4683 lcoreid_t lc_id; 4684 uint16_t nb_rx_queue, nb_tx_queue; 4685 uint16_t i, j, k, sm_id = 0; 4686 uint16_t total_tc_num; 4687 struct rte_port *port; 4688 uint8_t tc = 0; 4689 portid_t pid; 4690 int ret; 4691 4692 /* 4693 * The fwd_config_setup() is called when the port is RTE_PORT_STARTED 4694 * or RTE_PORT_STOPPED. 4695 * 4696 * Re-configure ports to get updated mapping between tc and queue in 4697 * case the queue number of the port is changed. Skip for started ports 4698 * since modifying queue number and calling dev_configure need to stop 4699 * ports first. 4700 */ 4701 for (pid = 0; pid < nb_fwd_ports; pid++) { 4702 if (port_is_started(pid) == 1) 4703 continue; 4704 4705 port = &ports[pid]; 4706 ret = rte_eth_dev_configure(pid, nb_rxq, nb_txq, 4707 &port->dev_conf); 4708 if (ret < 0) { 4709 fprintf(stderr, 4710 "Failed to re-configure port %d, ret = %d.\n", 4711 pid, ret); 4712 return; 4713 } 4714 } 4715 4716 cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores; 4717 cur_fwd_config.nb_fwd_ports = nb_fwd_ports; 4718 cur_fwd_config.nb_fwd_streams = 4719 (streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports); 4720 total_tc_num = get_fwd_port_total_tc_num(); 4721 if (cur_fwd_config.nb_fwd_lcores > total_tc_num) 4722 cur_fwd_config.nb_fwd_lcores = total_tc_num; 4723 4724 /* reinitialize forwarding streams */ 4725 init_fwd_streams(); 4726 sm_id = 0; 4727 txp = 1; 4728 /* get the dcb info on the first RX and TX ports */ 4729 (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info); 4730 (void)rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info); 4731 4732 for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) { 4733 fwd_lcores[lc_id]->stream_nb = 0; 4734 fwd_lcores[lc_id]->stream_idx = sm_id; 4735 for (i = 0; i < RTE_ETH_MAX_VMDQ_POOL; i++) { 4736 /* if the nb_queue is zero, means this tc is 4737 * not enabled on the POOL 4738 */ 4739 if (rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue == 0) 4740 break; 4741 k = fwd_lcores[lc_id]->stream_nb + 4742 fwd_lcores[lc_id]->stream_idx; 4743 rxq = rxp_dcb_info.tc_queue.tc_rxq[i][tc].base; 4744 txq = txp_dcb_info.tc_queue.tc_txq[i][tc].base; 4745 nb_rx_queue = txp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue; 4746 nb_tx_queue = txp_dcb_info.tc_queue.tc_txq[i][tc].nb_queue; 4747 for (j = 0; j < nb_rx_queue; j++) { 4748 struct fwd_stream *fs; 4749 4750 fs = fwd_streams[k + j]; 4751 fs->rx_port = fwd_ports_ids[rxp]; 4752 fs->rx_queue = rxq + j; 4753 fs->tx_port = fwd_ports_ids[txp]; 4754 fs->tx_queue = txq + j % nb_tx_queue; 4755 fs->peer_addr = fs->tx_port; 4756 fs->retry_enabled = retry_enabled; 4757 } 4758 fwd_lcores[lc_id]->stream_nb += 4759 rxp_dcb_info.tc_queue.tc_rxq[i][tc].nb_queue; 4760 } 4761 sm_id = (streamid_t) (sm_id + fwd_lcores[lc_id]->stream_nb); 4762 4763 tc++; 4764 if (tc < rxp_dcb_info.nb_tcs) 4765 continue; 4766 /* Restart from TC 0 on next RX port */ 4767 tc = 0; 4768 if (numa_support && (nb_fwd_ports <= (nb_ports >> 1))) 4769 rxp = (portid_t) 4770 (rxp + ((nb_ports >> 1) / nb_fwd_ports)); 4771 else 4772 rxp++; 4773 if (rxp >= nb_fwd_ports) 4774 return; 4775 /* get the dcb information on next RX and TX ports */ 4776 if ((rxp & 0x1) == 0) 4777 txp = (portid_t) (rxp + 1); 4778 else 4779 txp = (portid_t) (rxp - 1); 4780 rte_eth_dev_get_dcb_info(fwd_ports_ids[rxp], &rxp_dcb_info); 4781 rte_eth_dev_get_dcb_info(fwd_ports_ids[txp], &txp_dcb_info); 4782 } 4783 } 4784 4785 static void 4786 icmp_echo_config_setup(void) 4787 { 4788 portid_t rxp; 4789 queueid_t rxq; 4790 lcoreid_t lc_id; 4791 uint16_t sm_id; 4792 4793 if ((nb_txq * nb_fwd_ports) < nb_fwd_lcores) 4794 cur_fwd_config.nb_fwd_lcores = (lcoreid_t) 4795 (nb_txq * nb_fwd_ports); 4796 else 4797 cur_fwd_config.nb_fwd_lcores = (lcoreid_t) nb_fwd_lcores; 4798 cur_fwd_config.nb_fwd_ports = nb_fwd_ports; 4799 cur_fwd_config.nb_fwd_streams = 4800 (streamid_t) (nb_rxq * cur_fwd_config.nb_fwd_ports); 4801 if (cur_fwd_config.nb_fwd_streams < cur_fwd_config.nb_fwd_lcores) 4802 cur_fwd_config.nb_fwd_lcores = 4803 (lcoreid_t)cur_fwd_config.nb_fwd_streams; 4804 if (verbose_level > 0) { 4805 printf("%s fwd_cores=%d fwd_ports=%d fwd_streams=%d\n", 4806 __FUNCTION__, 4807 cur_fwd_config.nb_fwd_lcores, 4808 cur_fwd_config.nb_fwd_ports, 4809 cur_fwd_config.nb_fwd_streams); 4810 } 4811 4812 /* reinitialize forwarding streams */ 4813 init_fwd_streams(); 4814 setup_fwd_config_of_each_lcore(&cur_fwd_config); 4815 rxp = 0; rxq = 0; 4816 for (lc_id = 0; lc_id < cur_fwd_config.nb_fwd_lcores; lc_id++) { 4817 if (verbose_level > 0) 4818 printf(" core=%d: \n", lc_id); 4819 for (sm_id = 0; sm_id < fwd_lcores[lc_id]->stream_nb; sm_id++) { 4820 struct fwd_stream *fs; 4821 fs = fwd_streams[fwd_lcores[lc_id]->stream_idx + sm_id]; 4822 fs->rx_port = fwd_ports_ids[rxp]; 4823 fs->rx_queue = rxq; 4824 fs->tx_port = fs->rx_port; 4825 fs->tx_queue = rxq; 4826 fs->peer_addr = fs->tx_port; 4827 fs->retry_enabled = retry_enabled; 4828 if (verbose_level > 0) 4829 printf(" stream=%d port=%d rxq=%d txq=%d\n", 4830 sm_id, fs->rx_port, fs->rx_queue, 4831 fs->tx_queue); 4832 rxq = (queueid_t) (rxq + 1); 4833 if (rxq == nb_rxq) { 4834 rxq = 0; 4835 rxp = (portid_t) (rxp + 1); 4836 } 4837 } 4838 } 4839 } 4840 4841 void 4842 fwd_config_setup(void) 4843 { 4844 struct rte_port *port; 4845 portid_t pt_id; 4846 unsigned int i; 4847 4848 cur_fwd_config.fwd_eng = cur_fwd_eng; 4849 if (strcmp(cur_fwd_eng->fwd_mode_name, "icmpecho") == 0) { 4850 icmp_echo_config_setup(); 4851 return; 4852 } 4853 4854 if ((nb_rxq > 1) && (nb_txq > 1)){ 4855 if (dcb_config) { 4856 for (i = 0; i < nb_fwd_ports; i++) { 4857 pt_id = fwd_ports_ids[i]; 4858 port = &ports[pt_id]; 4859 if (!port->dcb_flag) { 4860 fprintf(stderr, 4861 "In DCB mode, all forwarding ports must be configured in this mode.\n"); 4862 return; 4863 } 4864 } 4865 if (nb_fwd_lcores == 1) { 4866 fprintf(stderr, 4867 "In DCB mode,the nb forwarding cores should be larger than 1.\n"); 4868 return; 4869 } 4870 4871 dcb_fwd_config_setup(); 4872 } else 4873 rss_fwd_config_setup(); 4874 } 4875 else 4876 simple_fwd_config_setup(); 4877 } 4878 4879 static const char * 4880 mp_alloc_to_str(uint8_t mode) 4881 { 4882 switch (mode) { 4883 case MP_ALLOC_NATIVE: 4884 return "native"; 4885 case MP_ALLOC_ANON: 4886 return "anon"; 4887 case MP_ALLOC_XMEM: 4888 return "xmem"; 4889 case MP_ALLOC_XMEM_HUGE: 4890 return "xmemhuge"; 4891 case MP_ALLOC_XBUF: 4892 return "xbuf"; 4893 default: 4894 return "invalid"; 4895 } 4896 } 4897 4898 void 4899 pkt_fwd_config_display(struct fwd_config *cfg) 4900 { 4901 struct fwd_stream *fs; 4902 lcoreid_t lc_id; 4903 streamid_t sm_id; 4904 4905 printf("%s packet forwarding%s - ports=%d - cores=%d - streams=%d - " 4906 "NUMA support %s, MP allocation mode: %s\n", 4907 cfg->fwd_eng->fwd_mode_name, 4908 retry_enabled == 0 ? "" : " with retry", 4909 cfg->nb_fwd_ports, cfg->nb_fwd_lcores, cfg->nb_fwd_streams, 4910 numa_support == 1 ? "enabled" : "disabled", 4911 mp_alloc_to_str(mp_alloc_type)); 4912 4913 if (retry_enabled) 4914 printf("TX retry num: %u, delay between TX retries: %uus\n", 4915 burst_tx_retry_num, burst_tx_delay_time); 4916 for (lc_id = 0; lc_id < cfg->nb_fwd_lcores; lc_id++) { 4917 printf("Logical Core %u (socket %u) forwards packets on " 4918 "%d streams:", 4919 fwd_lcores_cpuids[lc_id], 4920 rte_lcore_to_socket_id(fwd_lcores_cpuids[lc_id]), 4921 fwd_lcores[lc_id]->stream_nb); 4922 for (sm_id = 0; sm_id < fwd_lcores[lc_id]->stream_nb; sm_id++) { 4923 fs = fwd_streams[fwd_lcores[lc_id]->stream_idx + sm_id]; 4924 printf("\n RX P=%d/Q=%d (socket %u) -> TX " 4925 "P=%d/Q=%d (socket %u) ", 4926 fs->rx_port, fs->rx_queue, 4927 ports[fs->rx_port].socket_id, 4928 fs->tx_port, fs->tx_queue, 4929 ports[fs->tx_port].socket_id); 4930 print_ethaddr("peer=", 4931 &peer_eth_addrs[fs->peer_addr]); 4932 } 4933 printf("\n"); 4934 } 4935 printf("\n"); 4936 } 4937 4938 void 4939 set_fwd_eth_peer(portid_t port_id, char *peer_addr) 4940 { 4941 struct rte_ether_addr new_peer_addr; 4942 if (!rte_eth_dev_is_valid_port(port_id)) { 4943 fprintf(stderr, "Error: Invalid port number %i\n", port_id); 4944 return; 4945 } 4946 if (rte_ether_unformat_addr(peer_addr, &new_peer_addr) < 0) { 4947 fprintf(stderr, "Error: Invalid ethernet address: %s\n", 4948 peer_addr); 4949 return; 4950 } 4951 peer_eth_addrs[port_id] = new_peer_addr; 4952 } 4953 4954 int 4955 set_fwd_lcores_list(unsigned int *lcorelist, unsigned int nb_lc) 4956 { 4957 unsigned int i; 4958 unsigned int lcore_cpuid; 4959 int record_now; 4960 4961 record_now = 0; 4962 again: 4963 for (i = 0; i < nb_lc; i++) { 4964 lcore_cpuid = lcorelist[i]; 4965 if (! rte_lcore_is_enabled(lcore_cpuid)) { 4966 fprintf(stderr, "lcore %u not enabled\n", lcore_cpuid); 4967 return -1; 4968 } 4969 if (lcore_cpuid == rte_get_main_lcore()) { 4970 fprintf(stderr, 4971 "lcore %u cannot be masked on for running packet forwarding, which is the main lcore and reserved for command line parsing only\n", 4972 lcore_cpuid); 4973 return -1; 4974 } 4975 if (record_now) 4976 fwd_lcores_cpuids[i] = lcore_cpuid; 4977 } 4978 if (record_now == 0) { 4979 record_now = 1; 4980 goto again; 4981 } 4982 nb_cfg_lcores = (lcoreid_t) nb_lc; 4983 if (nb_fwd_lcores != (lcoreid_t) nb_lc) { 4984 printf("previous number of forwarding cores %u - changed to " 4985 "number of configured cores %u\n", 4986 (unsigned int) nb_fwd_lcores, nb_lc); 4987 nb_fwd_lcores = (lcoreid_t) nb_lc; 4988 } 4989 4990 return 0; 4991 } 4992 4993 int 4994 set_fwd_lcores_mask(uint64_t lcoremask) 4995 { 4996 unsigned int lcorelist[64]; 4997 unsigned int nb_lc; 4998 unsigned int i; 4999 5000 if (lcoremask == 0) { 5001 fprintf(stderr, "Invalid NULL mask of cores\n"); 5002 return -1; 5003 } 5004 nb_lc = 0; 5005 for (i = 0; i < 64; i++) { 5006 if (! ((uint64_t)(1ULL << i) & lcoremask)) 5007 continue; 5008 lcorelist[nb_lc++] = i; 5009 } 5010 return set_fwd_lcores_list(lcorelist, nb_lc); 5011 } 5012 5013 void 5014 set_fwd_lcores_number(uint16_t nb_lc) 5015 { 5016 if (test_done == 0) { 5017 fprintf(stderr, "Please stop forwarding first\n"); 5018 return; 5019 } 5020 if (nb_lc > nb_cfg_lcores) { 5021 fprintf(stderr, 5022 "nb fwd cores %u > %u (max. number of configured lcores) - ignored\n", 5023 (unsigned int) nb_lc, (unsigned int) nb_cfg_lcores); 5024 return; 5025 } 5026 nb_fwd_lcores = (lcoreid_t) nb_lc; 5027 printf("Number of forwarding cores set to %u\n", 5028 (unsigned int) nb_fwd_lcores); 5029 } 5030 5031 void 5032 set_fwd_ports_list(unsigned int *portlist, unsigned int nb_pt) 5033 { 5034 unsigned int i; 5035 portid_t port_id; 5036 int record_now; 5037 5038 record_now = 0; 5039 again: 5040 for (i = 0; i < nb_pt; i++) { 5041 port_id = (portid_t) portlist[i]; 5042 if (port_id_is_invalid(port_id, ENABLED_WARN)) 5043 return; 5044 if (record_now) 5045 fwd_ports_ids[i] = port_id; 5046 } 5047 if (record_now == 0) { 5048 record_now = 1; 5049 goto again; 5050 } 5051 nb_cfg_ports = (portid_t) nb_pt; 5052 if (nb_fwd_ports != (portid_t) nb_pt) { 5053 printf("previous number of forwarding ports %u - changed to " 5054 "number of configured ports %u\n", 5055 (unsigned int) nb_fwd_ports, nb_pt); 5056 nb_fwd_ports = (portid_t) nb_pt; 5057 } 5058 } 5059 5060 /** 5061 * Parse the user input and obtain the list of forwarding ports 5062 * 5063 * @param[in] list 5064 * String containing the user input. User can specify 5065 * in these formats 1,3,5 or 1-3 or 1-2,5 or 3,5-6. 5066 * For example, if the user wants to use all the available 5067 * 4 ports in his system, then the input can be 0-3 or 0,1,2,3. 5068 * If the user wants to use only the ports 1,2 then the input 5069 * is 1,2. 5070 * valid characters are '-' and ',' 5071 * @param[out] values 5072 * This array will be filled with a list of port IDs 5073 * based on the user input 5074 * Note that duplicate entries are discarded and only the first 5075 * count entries in this array are port IDs and all the rest 5076 * will contain default values 5077 * @param[in] maxsize 5078 * This parameter denotes 2 things 5079 * 1) Number of elements in the values array 5080 * 2) Maximum value of each element in the values array 5081 * @return 5082 * On success, returns total count of parsed port IDs 5083 * On failure, returns 0 5084 */ 5085 static unsigned int 5086 parse_port_list(const char *list, unsigned int *values, unsigned int maxsize) 5087 { 5088 unsigned int count = 0; 5089 char *end = NULL; 5090 int min, max; 5091 int value, i; 5092 unsigned int marked[maxsize]; 5093 5094 if (list == NULL || values == NULL) 5095 return 0; 5096 5097 for (i = 0; i < (int)maxsize; i++) 5098 marked[i] = 0; 5099 5100 min = INT_MAX; 5101 5102 do { 5103 /*Remove the blank spaces if any*/ 5104 while (isblank(*list)) 5105 list++; 5106 if (*list == '\0') 5107 break; 5108 errno = 0; 5109 value = strtol(list, &end, 10); 5110 if (errno || end == NULL) 5111 return 0; 5112 if (value < 0 || value >= (int)maxsize) 5113 return 0; 5114 while (isblank(*end)) 5115 end++; 5116 if (*end == '-' && min == INT_MAX) { 5117 min = value; 5118 } else if ((*end == ',') || (*end == '\0')) { 5119 max = value; 5120 if (min == INT_MAX) 5121 min = value; 5122 for (i = min; i <= max; i++) { 5123 if (count < maxsize) { 5124 if (marked[i]) 5125 continue; 5126 values[count] = i; 5127 marked[i] = 1; 5128 count++; 5129 } 5130 } 5131 min = INT_MAX; 5132 } else 5133 return 0; 5134 list = end + 1; 5135 } while (*end != '\0'); 5136 5137 return count; 5138 } 5139 5140 void 5141 parse_fwd_portlist(const char *portlist) 5142 { 5143 unsigned int portcount; 5144 unsigned int portindex[RTE_MAX_ETHPORTS]; 5145 unsigned int i, valid_port_count = 0; 5146 5147 portcount = parse_port_list(portlist, portindex, RTE_MAX_ETHPORTS); 5148 if (!portcount) 5149 rte_exit(EXIT_FAILURE, "Invalid fwd port list\n"); 5150 5151 /* 5152 * Here we verify the validity of the ports 5153 * and thereby calculate the total number of 5154 * valid ports 5155 */ 5156 for (i = 0; i < portcount && i < RTE_DIM(portindex); i++) { 5157 if (rte_eth_dev_is_valid_port(portindex[i])) { 5158 portindex[valid_port_count] = portindex[i]; 5159 valid_port_count++; 5160 } 5161 } 5162 5163 set_fwd_ports_list(portindex, valid_port_count); 5164 } 5165 5166 void 5167 set_fwd_ports_mask(uint64_t portmask) 5168 { 5169 unsigned int portlist[64]; 5170 unsigned int nb_pt; 5171 unsigned int i; 5172 5173 if (portmask == 0) { 5174 fprintf(stderr, "Invalid NULL mask of ports\n"); 5175 return; 5176 } 5177 nb_pt = 0; 5178 RTE_ETH_FOREACH_DEV(i) { 5179 if (! ((uint64_t)(1ULL << i) & portmask)) 5180 continue; 5181 portlist[nb_pt++] = i; 5182 } 5183 set_fwd_ports_list(portlist, nb_pt); 5184 } 5185 5186 void 5187 set_fwd_ports_number(uint16_t nb_pt) 5188 { 5189 if (nb_pt > nb_cfg_ports) { 5190 fprintf(stderr, 5191 "nb fwd ports %u > %u (number of configured ports) - ignored\n", 5192 (unsigned int) nb_pt, (unsigned int) nb_cfg_ports); 5193 return; 5194 } 5195 nb_fwd_ports = (portid_t) nb_pt; 5196 printf("Number of forwarding ports set to %u\n", 5197 (unsigned int) nb_fwd_ports); 5198 } 5199 5200 int 5201 port_is_forwarding(portid_t port_id) 5202 { 5203 unsigned int i; 5204 5205 if (port_id_is_invalid(port_id, ENABLED_WARN)) 5206 return -1; 5207 5208 for (i = 0; i < nb_fwd_ports; i++) { 5209 if (fwd_ports_ids[i] == port_id) 5210 return 1; 5211 } 5212 5213 return 0; 5214 } 5215 5216 void 5217 set_nb_pkt_per_burst(uint16_t nb) 5218 { 5219 if (nb > MAX_PKT_BURST) { 5220 fprintf(stderr, 5221 "nb pkt per burst: %u > %u (maximum packet per burst) ignored\n", 5222 (unsigned int) nb, (unsigned int) MAX_PKT_BURST); 5223 return; 5224 } 5225 nb_pkt_per_burst = nb; 5226 printf("Number of packets per burst set to %u\n", 5227 (unsigned int) nb_pkt_per_burst); 5228 } 5229 5230 static const char * 5231 tx_split_get_name(enum tx_pkt_split split) 5232 { 5233 uint32_t i; 5234 5235 for (i = 0; i != RTE_DIM(tx_split_name); i++) { 5236 if (tx_split_name[i].split == split) 5237 return tx_split_name[i].name; 5238 } 5239 return NULL; 5240 } 5241 5242 void 5243 set_tx_pkt_split(const char *name) 5244 { 5245 uint32_t i; 5246 5247 for (i = 0; i != RTE_DIM(tx_split_name); i++) { 5248 if (strcmp(tx_split_name[i].name, name) == 0) { 5249 tx_pkt_split = tx_split_name[i].split; 5250 return; 5251 } 5252 } 5253 fprintf(stderr, "unknown value: \"%s\"\n", name); 5254 } 5255 5256 int 5257 parse_fec_mode(const char *name, uint32_t *fec_capa) 5258 { 5259 uint8_t i; 5260 5261 for (i = 0; i < RTE_DIM(fec_mode_name); i++) { 5262 if (strcmp(fec_mode_name[i].name, name) == 0) { 5263 *fec_capa = 5264 RTE_ETH_FEC_MODE_TO_CAPA(fec_mode_name[i].mode); 5265 return 0; 5266 } 5267 } 5268 return -1; 5269 } 5270 5271 void 5272 show_fec_capability(unsigned int num, struct rte_eth_fec_capa *speed_fec_capa) 5273 { 5274 unsigned int i, j; 5275 5276 printf("FEC capabilities:\n"); 5277 5278 for (i = 0; i < num; i++) { 5279 printf("%s : ", 5280 rte_eth_link_speed_to_str(speed_fec_capa[i].speed)); 5281 5282 for (j = 0; j < RTE_DIM(fec_mode_name); j++) { 5283 if (RTE_ETH_FEC_MODE_TO_CAPA(j) & 5284 speed_fec_capa[i].capa) 5285 printf("%s ", fec_mode_name[j].name); 5286 } 5287 printf("\n"); 5288 } 5289 } 5290 5291 void 5292 show_rx_pkt_offsets(void) 5293 { 5294 uint32_t i, n; 5295 5296 n = rx_pkt_nb_offs; 5297 printf("Number of offsets: %u\n", n); 5298 if (n) { 5299 printf("Segment offsets: "); 5300 for (i = 0; i != n - 1; i++) 5301 printf("%hu,", rx_pkt_seg_offsets[i]); 5302 printf("%hu\n", rx_pkt_seg_lengths[i]); 5303 } 5304 } 5305 5306 void 5307 set_rx_pkt_offsets(unsigned int *seg_offsets, unsigned int nb_offs) 5308 { 5309 unsigned int i; 5310 5311 if (nb_offs >= MAX_SEGS_BUFFER_SPLIT) { 5312 printf("nb segments per RX packets=%u >= " 5313 "MAX_SEGS_BUFFER_SPLIT - ignored\n", nb_offs); 5314 return; 5315 } 5316 5317 /* 5318 * No extra check here, the segment length will be checked by PMD 5319 * in the extended queue setup. 5320 */ 5321 for (i = 0; i < nb_offs; i++) { 5322 if (seg_offsets[i] >= UINT16_MAX) { 5323 printf("offset[%u]=%u > UINT16_MAX - give up\n", 5324 i, seg_offsets[i]); 5325 return; 5326 } 5327 } 5328 5329 for (i = 0; i < nb_offs; i++) 5330 rx_pkt_seg_offsets[i] = (uint16_t) seg_offsets[i]; 5331 5332 rx_pkt_nb_offs = (uint8_t) nb_offs; 5333 } 5334 5335 void 5336 show_rx_pkt_segments(void) 5337 { 5338 uint32_t i, n; 5339 5340 n = rx_pkt_nb_segs; 5341 printf("Number of segments: %u\n", n); 5342 if (n) { 5343 printf("Segment sizes: "); 5344 for (i = 0; i != n - 1; i++) 5345 printf("%hu,", rx_pkt_seg_lengths[i]); 5346 printf("%hu\n", rx_pkt_seg_lengths[i]); 5347 } 5348 } 5349 5350 static const char *get_ptype_str(uint32_t ptype) 5351 { 5352 const char *str; 5353 5354 switch (ptype) { 5355 case RTE_PTYPE_L2_ETHER: 5356 str = "eth"; 5357 break; 5358 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN: 5359 str = "ipv4"; 5360 break; 5361 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN: 5362 str = "ipv6"; 5363 break; 5364 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_TCP: 5365 str = "ipv4-tcp"; 5366 break; 5367 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_UDP: 5368 str = "ipv4-udp"; 5369 break; 5370 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L4_SCTP: 5371 str = "ipv4-sctp"; 5372 break; 5373 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_TCP: 5374 str = "ipv6-tcp"; 5375 break; 5376 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_UDP: 5377 str = "ipv6-udp"; 5378 break; 5379 case RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L4_SCTP: 5380 str = "ipv6-sctp"; 5381 break; 5382 case RTE_PTYPE_TUNNEL_GRENAT: 5383 str = "grenat"; 5384 break; 5385 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER: 5386 str = "inner-eth"; 5387 break; 5388 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER 5389 | RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN: 5390 str = "inner-ipv4"; 5391 break; 5392 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER 5393 | RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN: 5394 str = "inner-ipv6"; 5395 break; 5396 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | 5397 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP: 5398 str = "inner-ipv4-tcp"; 5399 break; 5400 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | 5401 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP: 5402 str = "inner-ipv4-udp"; 5403 break; 5404 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | 5405 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP: 5406 str = "inner-ipv4-sctp"; 5407 break; 5408 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | 5409 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_TCP: 5410 str = "inner-ipv6-tcp"; 5411 break; 5412 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | 5413 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_UDP: 5414 str = "inner-ipv6-udp"; 5415 break; 5416 case RTE_PTYPE_TUNNEL_GRENAT | RTE_PTYPE_INNER_L2_ETHER | 5417 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_INNER_L4_SCTP: 5418 str = "inner-ipv6-sctp"; 5419 break; 5420 default: 5421 str = "unsupported"; 5422 } 5423 5424 return str; 5425 } 5426 5427 void 5428 show_rx_pkt_hdrs(void) 5429 { 5430 uint32_t i, n; 5431 5432 n = rx_pkt_nb_segs; 5433 printf("Number of segments: %u\n", n); 5434 if (n) { 5435 printf("Packet segs: "); 5436 for (i = 0; i < n - 1; i++) 5437 printf("%s, ", get_ptype_str(rx_pkt_hdr_protos[i])); 5438 printf("payload\n"); 5439 } 5440 } 5441 5442 void 5443 set_rx_pkt_hdrs(unsigned int *seg_hdrs, unsigned int nb_segs) 5444 { 5445 unsigned int i; 5446 5447 if (nb_segs + 1 > MAX_SEGS_BUFFER_SPLIT) { 5448 printf("nb segments per RX packets=%u > " 5449 "MAX_SEGS_BUFFER_SPLIT - ignored\n", nb_segs + 1); 5450 return; 5451 } 5452 5453 memset(rx_pkt_hdr_protos, 0, sizeof(rx_pkt_hdr_protos)); 5454 5455 for (i = 0; i < nb_segs; i++) 5456 rx_pkt_hdr_protos[i] = (uint32_t)seg_hdrs[i]; 5457 /* 5458 * We calculate the number of hdrs, but payload is not included, 5459 * so rx_pkt_nb_segs would increase 1. 5460 */ 5461 rx_pkt_nb_segs = nb_segs + 1; 5462 } 5463 5464 void 5465 set_rx_pkt_segments(unsigned int *seg_lengths, unsigned int nb_segs) 5466 { 5467 unsigned int i; 5468 5469 if (nb_segs >= MAX_SEGS_BUFFER_SPLIT) { 5470 printf("nb segments per RX packets=%u >= " 5471 "MAX_SEGS_BUFFER_SPLIT - ignored\n", nb_segs); 5472 return; 5473 } 5474 5475 /* 5476 * No extra check here, the segment length will be checked by PMD 5477 * in the extended queue setup. 5478 */ 5479 for (i = 0; i < nb_segs; i++) { 5480 if (seg_lengths[i] >= UINT16_MAX) { 5481 printf("length[%u]=%u > UINT16_MAX - give up\n", 5482 i, seg_lengths[i]); 5483 return; 5484 } 5485 } 5486 5487 for (i = 0; i < nb_segs; i++) 5488 rx_pkt_seg_lengths[i] = (uint16_t) seg_lengths[i]; 5489 5490 rx_pkt_nb_segs = (uint8_t) nb_segs; 5491 } 5492 5493 void 5494 show_tx_pkt_segments(void) 5495 { 5496 uint32_t i, n; 5497 const char *split; 5498 5499 n = tx_pkt_nb_segs; 5500 split = tx_split_get_name(tx_pkt_split); 5501 5502 printf("Number of segments: %u\n", n); 5503 printf("Segment sizes: "); 5504 for (i = 0; i != n - 1; i++) 5505 printf("%hu,", tx_pkt_seg_lengths[i]); 5506 printf("%hu\n", tx_pkt_seg_lengths[i]); 5507 printf("Split packet: %s\n", split); 5508 } 5509 5510 static bool 5511 nb_segs_is_invalid(unsigned int nb_segs) 5512 { 5513 uint16_t ring_size; 5514 uint16_t queue_id; 5515 uint16_t port_id; 5516 int ret; 5517 5518 RTE_ETH_FOREACH_DEV(port_id) { 5519 for (queue_id = 0; queue_id < nb_txq; queue_id++) { 5520 ret = get_tx_ring_size(port_id, queue_id, &ring_size); 5521 if (ret) { 5522 /* Port may not be initialized yet, can't say 5523 * the port is invalid in this stage. 5524 */ 5525 continue; 5526 } 5527 if (ring_size < nb_segs) { 5528 printf("nb segments per TX packets=%u >= TX " 5529 "queue(%u) ring_size=%u - txpkts ignored\n", 5530 nb_segs, queue_id, ring_size); 5531 return true; 5532 } 5533 } 5534 } 5535 5536 return false; 5537 } 5538 5539 void 5540 set_tx_pkt_segments(unsigned int *seg_lengths, unsigned int nb_segs) 5541 { 5542 uint16_t tx_pkt_len; 5543 unsigned int i; 5544 5545 /* 5546 * For single segment settings failed check is ignored. 5547 * It is a very basic capability to send the single segment 5548 * packets, suppose it is always supported. 5549 */ 5550 if (nb_segs > 1 && nb_segs_is_invalid(nb_segs)) { 5551 fprintf(stderr, 5552 "Tx segment size(%u) is not supported - txpkts ignored\n", 5553 nb_segs); 5554 return; 5555 } 5556 5557 if (nb_segs > RTE_MAX_SEGS_PER_PKT) { 5558 fprintf(stderr, 5559 "Tx segment size(%u) is bigger than max number of segment(%u)\n", 5560 nb_segs, RTE_MAX_SEGS_PER_PKT); 5561 return; 5562 } 5563 5564 /* 5565 * Check that each segment length is greater or equal than 5566 * the mbuf data size. 5567 * Check also that the total packet length is greater or equal than the 5568 * size of an empty UDP/IP packet (sizeof(struct rte_ether_hdr) + 5569 * 20 + 8). 5570 */ 5571 tx_pkt_len = 0; 5572 for (i = 0; i < nb_segs; i++) { 5573 if (seg_lengths[i] > mbuf_data_size[0]) { 5574 fprintf(stderr, 5575 "length[%u]=%u > mbuf_data_size=%u - give up\n", 5576 i, seg_lengths[i], mbuf_data_size[0]); 5577 return; 5578 } 5579 tx_pkt_len = (uint16_t)(tx_pkt_len + seg_lengths[i]); 5580 } 5581 if (tx_pkt_len < (sizeof(struct rte_ether_hdr) + 20 + 8)) { 5582 fprintf(stderr, "total packet length=%u < %d - give up\n", 5583 (unsigned) tx_pkt_len, 5584 (int)(sizeof(struct rte_ether_hdr) + 20 + 8)); 5585 return; 5586 } 5587 5588 for (i = 0; i < nb_segs; i++) 5589 tx_pkt_seg_lengths[i] = (uint16_t) seg_lengths[i]; 5590 5591 tx_pkt_length = tx_pkt_len; 5592 tx_pkt_nb_segs = (uint8_t) nb_segs; 5593 } 5594 5595 void 5596 show_tx_pkt_times(void) 5597 { 5598 printf("Interburst gap: %u\n", tx_pkt_times_inter); 5599 printf("Intraburst gap: %u\n", tx_pkt_times_intra); 5600 } 5601 5602 void 5603 set_tx_pkt_times(unsigned int *tx_times) 5604 { 5605 tx_pkt_times_inter = tx_times[0]; 5606 tx_pkt_times_intra = tx_times[1]; 5607 } 5608 5609 #ifdef RTE_LIB_GRO 5610 void 5611 setup_gro(const char *onoff, portid_t port_id) 5612 { 5613 if (!rte_eth_dev_is_valid_port(port_id)) { 5614 fprintf(stderr, "invalid port id %u\n", port_id); 5615 return; 5616 } 5617 if (test_done == 0) { 5618 fprintf(stderr, 5619 "Before enable/disable GRO, please stop forwarding first\n"); 5620 return; 5621 } 5622 if (strcmp(onoff, "on") == 0) { 5623 if (gro_ports[port_id].enable != 0) { 5624 fprintf(stderr, 5625 "Port %u has enabled GRO. Please disable GRO first\n", 5626 port_id); 5627 return; 5628 } 5629 if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) { 5630 gro_ports[port_id].param.gro_types = RTE_GRO_TCP_IPV4; 5631 gro_ports[port_id].param.max_flow_num = 5632 GRO_DEFAULT_FLOW_NUM; 5633 gro_ports[port_id].param.max_item_per_flow = 5634 GRO_DEFAULT_ITEM_NUM_PER_FLOW; 5635 } 5636 gro_ports[port_id].enable = 1; 5637 } else { 5638 if (gro_ports[port_id].enable == 0) { 5639 fprintf(stderr, "Port %u has disabled GRO\n", port_id); 5640 return; 5641 } 5642 gro_ports[port_id].enable = 0; 5643 } 5644 } 5645 5646 void 5647 setup_gro_flush_cycles(uint8_t cycles) 5648 { 5649 if (test_done == 0) { 5650 fprintf(stderr, 5651 "Before change flush interval for GRO, please stop forwarding first.\n"); 5652 return; 5653 } 5654 5655 if (cycles > GRO_MAX_FLUSH_CYCLES || cycles < 5656 GRO_DEFAULT_FLUSH_CYCLES) { 5657 fprintf(stderr, 5658 "The flushing cycle be in the range of 1 to %u. Revert to the default value %u.\n", 5659 GRO_MAX_FLUSH_CYCLES, GRO_DEFAULT_FLUSH_CYCLES); 5660 cycles = GRO_DEFAULT_FLUSH_CYCLES; 5661 } 5662 5663 gro_flush_cycles = cycles; 5664 } 5665 5666 void 5667 show_gro(portid_t port_id) 5668 { 5669 struct rte_gro_param *param; 5670 uint32_t max_pkts_num; 5671 5672 param = &gro_ports[port_id].param; 5673 5674 if (!rte_eth_dev_is_valid_port(port_id)) { 5675 fprintf(stderr, "Invalid port id %u.\n", port_id); 5676 return; 5677 } 5678 if (gro_ports[port_id].enable) { 5679 printf("GRO type: TCP/IPv4\n"); 5680 if (gro_flush_cycles == GRO_DEFAULT_FLUSH_CYCLES) { 5681 max_pkts_num = param->max_flow_num * 5682 param->max_item_per_flow; 5683 } else 5684 max_pkts_num = MAX_PKT_BURST * GRO_MAX_FLUSH_CYCLES; 5685 printf("Max number of packets to perform GRO: %u\n", 5686 max_pkts_num); 5687 printf("Flushing cycles: %u\n", gro_flush_cycles); 5688 } else 5689 printf("Port %u doesn't enable GRO.\n", port_id); 5690 } 5691 #endif /* RTE_LIB_GRO */ 5692 5693 #ifdef RTE_LIB_GSO 5694 void 5695 setup_gso(const char *mode, portid_t port_id) 5696 { 5697 if (!rte_eth_dev_is_valid_port(port_id)) { 5698 fprintf(stderr, "invalid port id %u\n", port_id); 5699 return; 5700 } 5701 if (strcmp(mode, "on") == 0) { 5702 if (test_done == 0) { 5703 fprintf(stderr, 5704 "before enabling GSO, please stop forwarding first\n"); 5705 return; 5706 } 5707 gso_ports[port_id].enable = 1; 5708 } else if (strcmp(mode, "off") == 0) { 5709 if (test_done == 0) { 5710 fprintf(stderr, 5711 "before disabling GSO, please stop forwarding first\n"); 5712 return; 5713 } 5714 gso_ports[port_id].enable = 0; 5715 } 5716 } 5717 #endif /* RTE_LIB_GSO */ 5718 5719 char* 5720 list_pkt_forwarding_modes(void) 5721 { 5722 static char fwd_modes[128] = ""; 5723 const char *separator = "|"; 5724 struct fwd_engine *fwd_eng; 5725 unsigned i = 0; 5726 5727 if (strlen (fwd_modes) == 0) { 5728 while ((fwd_eng = fwd_engines[i++]) != NULL) { 5729 strncat(fwd_modes, fwd_eng->fwd_mode_name, 5730 sizeof(fwd_modes) - strlen(fwd_modes) - 1); 5731 strncat(fwd_modes, separator, 5732 sizeof(fwd_modes) - strlen(fwd_modes) - 1); 5733 } 5734 fwd_modes[strlen(fwd_modes) - strlen(separator)] = '\0'; 5735 } 5736 5737 return fwd_modes; 5738 } 5739 5740 char* 5741 list_pkt_forwarding_retry_modes(void) 5742 { 5743 static char fwd_modes[128] = ""; 5744 const char *separator = "|"; 5745 struct fwd_engine *fwd_eng; 5746 unsigned i = 0; 5747 5748 if (strlen(fwd_modes) == 0) { 5749 while ((fwd_eng = fwd_engines[i++]) != NULL) { 5750 if (fwd_eng == &rx_only_engine) 5751 continue; 5752 strncat(fwd_modes, fwd_eng->fwd_mode_name, 5753 sizeof(fwd_modes) - 5754 strlen(fwd_modes) - 1); 5755 strncat(fwd_modes, separator, 5756 sizeof(fwd_modes) - 5757 strlen(fwd_modes) - 1); 5758 } 5759 fwd_modes[strlen(fwd_modes) - strlen(separator)] = '\0'; 5760 } 5761 5762 return fwd_modes; 5763 } 5764 5765 void 5766 set_pkt_forwarding_mode(const char *fwd_mode_name) 5767 { 5768 struct fwd_engine *fwd_eng; 5769 unsigned i; 5770 5771 i = 0; 5772 while ((fwd_eng = fwd_engines[i]) != NULL) { 5773 if (! strcmp(fwd_eng->fwd_mode_name, fwd_mode_name)) { 5774 printf("Set %s packet forwarding mode%s\n", 5775 fwd_mode_name, 5776 retry_enabled == 0 ? "" : " with retry"); 5777 cur_fwd_eng = fwd_eng; 5778 return; 5779 } 5780 i++; 5781 } 5782 fprintf(stderr, "Invalid %s packet forwarding mode\n", fwd_mode_name); 5783 } 5784 5785 void 5786 add_rx_dump_callbacks(portid_t portid) 5787 { 5788 struct rte_eth_dev_info dev_info; 5789 uint16_t queue; 5790 int ret; 5791 5792 if (port_id_is_invalid(portid, ENABLED_WARN)) 5793 return; 5794 5795 ret = eth_dev_info_get_print_err(portid, &dev_info); 5796 if (ret != 0) 5797 return; 5798 5799 for (queue = 0; queue < dev_info.nb_rx_queues; queue++) 5800 if (!ports[portid].rx_dump_cb[queue]) 5801 ports[portid].rx_dump_cb[queue] = 5802 rte_eth_add_rx_callback(portid, queue, 5803 dump_rx_pkts, NULL); 5804 } 5805 5806 void 5807 add_tx_dump_callbacks(portid_t portid) 5808 { 5809 struct rte_eth_dev_info dev_info; 5810 uint16_t queue; 5811 int ret; 5812 5813 if (port_id_is_invalid(portid, ENABLED_WARN)) 5814 return; 5815 5816 ret = eth_dev_info_get_print_err(portid, &dev_info); 5817 if (ret != 0) 5818 return; 5819 5820 for (queue = 0; queue < dev_info.nb_tx_queues; queue++) 5821 if (!ports[portid].tx_dump_cb[queue]) 5822 ports[portid].tx_dump_cb[queue] = 5823 rte_eth_add_tx_callback(portid, queue, 5824 dump_tx_pkts, NULL); 5825 } 5826 5827 void 5828 remove_rx_dump_callbacks(portid_t portid) 5829 { 5830 struct rte_eth_dev_info dev_info; 5831 uint16_t queue; 5832 int ret; 5833 5834 if (port_id_is_invalid(portid, ENABLED_WARN)) 5835 return; 5836 5837 ret = eth_dev_info_get_print_err(portid, &dev_info); 5838 if (ret != 0) 5839 return; 5840 5841 for (queue = 0; queue < dev_info.nb_rx_queues; queue++) 5842 if (ports[portid].rx_dump_cb[queue]) { 5843 rte_eth_remove_rx_callback(portid, queue, 5844 ports[portid].rx_dump_cb[queue]); 5845 ports[portid].rx_dump_cb[queue] = NULL; 5846 } 5847 } 5848 5849 void 5850 remove_tx_dump_callbacks(portid_t portid) 5851 { 5852 struct rte_eth_dev_info dev_info; 5853 uint16_t queue; 5854 int ret; 5855 5856 if (port_id_is_invalid(portid, ENABLED_WARN)) 5857 return; 5858 5859 ret = eth_dev_info_get_print_err(portid, &dev_info); 5860 if (ret != 0) 5861 return; 5862 5863 for (queue = 0; queue < dev_info.nb_tx_queues; queue++) 5864 if (ports[portid].tx_dump_cb[queue]) { 5865 rte_eth_remove_tx_callback(portid, queue, 5866 ports[portid].tx_dump_cb[queue]); 5867 ports[portid].tx_dump_cb[queue] = NULL; 5868 } 5869 } 5870 5871 void 5872 configure_rxtx_dump_callbacks(uint16_t verbose) 5873 { 5874 portid_t portid; 5875 5876 #ifndef RTE_ETHDEV_RXTX_CALLBACKS 5877 TESTPMD_LOG(ERR, "setting rxtx callbacks is not enabled\n"); 5878 return; 5879 #endif 5880 5881 RTE_ETH_FOREACH_DEV(portid) 5882 { 5883 if (verbose == 1 || verbose > 2) 5884 add_rx_dump_callbacks(portid); 5885 else 5886 remove_rx_dump_callbacks(portid); 5887 if (verbose >= 2) 5888 add_tx_dump_callbacks(portid); 5889 else 5890 remove_tx_dump_callbacks(portid); 5891 } 5892 } 5893 5894 void 5895 set_verbose_level(uint16_t vb_level) 5896 { 5897 printf("Change verbose level from %u to %u\n", 5898 (unsigned int) verbose_level, (unsigned int) vb_level); 5899 verbose_level = vb_level; 5900 configure_rxtx_dump_callbacks(verbose_level); 5901 } 5902 5903 void 5904 vlan_extend_set(portid_t port_id, int on) 5905 { 5906 int diag; 5907 int vlan_offload; 5908 uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads; 5909 5910 if (port_id_is_invalid(port_id, ENABLED_WARN)) 5911 return; 5912 5913 vlan_offload = rte_eth_dev_get_vlan_offload(port_id); 5914 5915 if (on) { 5916 vlan_offload |= RTE_ETH_VLAN_EXTEND_OFFLOAD; 5917 port_rx_offloads |= RTE_ETH_RX_OFFLOAD_VLAN_EXTEND; 5918 } else { 5919 vlan_offload &= ~RTE_ETH_VLAN_EXTEND_OFFLOAD; 5920 port_rx_offloads &= ~RTE_ETH_RX_OFFLOAD_VLAN_EXTEND; 5921 } 5922 5923 diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); 5924 if (diag < 0) { 5925 fprintf(stderr, 5926 "rx_vlan_extend_set(port_pi=%d, on=%d) failed diag=%d\n", 5927 port_id, on, diag); 5928 return; 5929 } 5930 ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; 5931 } 5932 5933 void 5934 rx_vlan_strip_set(portid_t port_id, int on) 5935 { 5936 int diag; 5937 int vlan_offload; 5938 uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads; 5939 5940 if (port_id_is_invalid(port_id, ENABLED_WARN)) 5941 return; 5942 5943 vlan_offload = rte_eth_dev_get_vlan_offload(port_id); 5944 5945 if (on) { 5946 vlan_offload |= RTE_ETH_VLAN_STRIP_OFFLOAD; 5947 port_rx_offloads |= RTE_ETH_RX_OFFLOAD_VLAN_STRIP; 5948 } else { 5949 vlan_offload &= ~RTE_ETH_VLAN_STRIP_OFFLOAD; 5950 port_rx_offloads &= ~RTE_ETH_RX_OFFLOAD_VLAN_STRIP; 5951 } 5952 5953 diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); 5954 if (diag < 0) { 5955 fprintf(stderr, 5956 "%s(port_pi=%d, on=%d) failed diag=%d\n", 5957 __func__, port_id, on, diag); 5958 return; 5959 } 5960 ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; 5961 } 5962 5963 void 5964 rx_vlan_strip_set_on_queue(portid_t port_id, uint16_t queue_id, int on) 5965 { 5966 int diag; 5967 5968 if (port_id_is_invalid(port_id, ENABLED_WARN)) 5969 return; 5970 5971 diag = rte_eth_dev_set_vlan_strip_on_queue(port_id, queue_id, on); 5972 if (diag < 0) 5973 fprintf(stderr, 5974 "%s(port_pi=%d, queue_id=%d, on=%d) failed diag=%d\n", 5975 __func__, port_id, queue_id, on, diag); 5976 } 5977 5978 void 5979 rx_vlan_filter_set(portid_t port_id, int on) 5980 { 5981 int diag; 5982 int vlan_offload; 5983 uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads; 5984 5985 if (port_id_is_invalid(port_id, ENABLED_WARN)) 5986 return; 5987 5988 vlan_offload = rte_eth_dev_get_vlan_offload(port_id); 5989 5990 if (on) { 5991 vlan_offload |= RTE_ETH_VLAN_FILTER_OFFLOAD; 5992 port_rx_offloads |= RTE_ETH_RX_OFFLOAD_VLAN_FILTER; 5993 } else { 5994 vlan_offload &= ~RTE_ETH_VLAN_FILTER_OFFLOAD; 5995 port_rx_offloads &= ~RTE_ETH_RX_OFFLOAD_VLAN_FILTER; 5996 } 5997 5998 diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); 5999 if (diag < 0) { 6000 fprintf(stderr, 6001 "%s(port_pi=%d, on=%d) failed diag=%d\n", 6002 __func__, port_id, on, diag); 6003 return; 6004 } 6005 ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; 6006 } 6007 6008 void 6009 rx_vlan_qinq_strip_set(portid_t port_id, int on) 6010 { 6011 int diag; 6012 int vlan_offload; 6013 uint64_t port_rx_offloads = ports[port_id].dev_conf.rxmode.offloads; 6014 6015 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6016 return; 6017 6018 vlan_offload = rte_eth_dev_get_vlan_offload(port_id); 6019 6020 if (on) { 6021 vlan_offload |= RTE_ETH_QINQ_STRIP_OFFLOAD; 6022 port_rx_offloads |= RTE_ETH_RX_OFFLOAD_QINQ_STRIP; 6023 } else { 6024 vlan_offload &= ~RTE_ETH_QINQ_STRIP_OFFLOAD; 6025 port_rx_offloads &= ~RTE_ETH_RX_OFFLOAD_QINQ_STRIP; 6026 } 6027 6028 diag = rte_eth_dev_set_vlan_offload(port_id, vlan_offload); 6029 if (diag < 0) { 6030 fprintf(stderr, "%s(port_pi=%d, on=%d) failed diag=%d\n", 6031 __func__, port_id, on, diag); 6032 return; 6033 } 6034 ports[port_id].dev_conf.rxmode.offloads = port_rx_offloads; 6035 } 6036 6037 int 6038 rx_vft_set(portid_t port_id, uint16_t vlan_id, int on) 6039 { 6040 int diag; 6041 6042 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6043 return 1; 6044 if (vlan_id_is_invalid(vlan_id)) 6045 return 1; 6046 diag = rte_eth_dev_vlan_filter(port_id, vlan_id, on); 6047 if (diag == 0) 6048 return 0; 6049 fprintf(stderr, 6050 "rte_eth_dev_vlan_filter(port_pi=%d, vlan_id=%d, on=%d) failed diag=%d\n", 6051 port_id, vlan_id, on, diag); 6052 return -1; 6053 } 6054 6055 void 6056 rx_vlan_all_filter_set(portid_t port_id, int on) 6057 { 6058 uint16_t vlan_id; 6059 6060 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6061 return; 6062 for (vlan_id = 0; vlan_id < 4096; vlan_id++) { 6063 if (rx_vft_set(port_id, vlan_id, on)) 6064 break; 6065 } 6066 } 6067 6068 void 6069 vlan_tpid_set(portid_t port_id, enum rte_vlan_type vlan_type, uint16_t tp_id) 6070 { 6071 int diag; 6072 6073 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6074 return; 6075 6076 diag = rte_eth_dev_set_vlan_ether_type(port_id, vlan_type, tp_id); 6077 if (diag == 0) 6078 return; 6079 6080 fprintf(stderr, 6081 "tx_vlan_tpid_set(port_pi=%d, vlan_type=%d, tpid=%d) failed diag=%d\n", 6082 port_id, vlan_type, tp_id, diag); 6083 } 6084 6085 void 6086 tx_vlan_set(portid_t port_id, uint16_t vlan_id) 6087 { 6088 struct rte_eth_dev_info dev_info; 6089 int ret; 6090 6091 if (vlan_id_is_invalid(vlan_id)) 6092 return; 6093 6094 if (ports[port_id].dev_conf.txmode.offloads & 6095 RTE_ETH_TX_OFFLOAD_QINQ_INSERT) { 6096 fprintf(stderr, "Error, as QinQ has been enabled.\n"); 6097 return; 6098 } 6099 6100 ret = eth_dev_info_get_print_err(port_id, &dev_info); 6101 if (ret != 0) 6102 return; 6103 6104 if ((dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_VLAN_INSERT) == 0) { 6105 fprintf(stderr, 6106 "Error: vlan insert is not supported by port %d\n", 6107 port_id); 6108 return; 6109 } 6110 6111 tx_vlan_reset(port_id); 6112 ports[port_id].dev_conf.txmode.offloads |= RTE_ETH_TX_OFFLOAD_VLAN_INSERT; 6113 ports[port_id].tx_vlan_id = vlan_id; 6114 } 6115 6116 void 6117 tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer) 6118 { 6119 struct rte_eth_dev_info dev_info; 6120 int ret; 6121 6122 if (vlan_id_is_invalid(vlan_id)) 6123 return; 6124 if (vlan_id_is_invalid(vlan_id_outer)) 6125 return; 6126 6127 ret = eth_dev_info_get_print_err(port_id, &dev_info); 6128 if (ret != 0) 6129 return; 6130 6131 if ((dev_info.tx_offload_capa & RTE_ETH_TX_OFFLOAD_QINQ_INSERT) == 0) { 6132 fprintf(stderr, 6133 "Error: qinq insert not supported by port %d\n", 6134 port_id); 6135 return; 6136 } 6137 6138 tx_vlan_reset(port_id); 6139 ports[port_id].dev_conf.txmode.offloads |= (RTE_ETH_TX_OFFLOAD_VLAN_INSERT | 6140 RTE_ETH_TX_OFFLOAD_QINQ_INSERT); 6141 ports[port_id].tx_vlan_id = vlan_id; 6142 ports[port_id].tx_vlan_id_outer = vlan_id_outer; 6143 } 6144 6145 void 6146 tx_vlan_reset(portid_t port_id) 6147 { 6148 ports[port_id].dev_conf.txmode.offloads &= 6149 ~(RTE_ETH_TX_OFFLOAD_VLAN_INSERT | 6150 RTE_ETH_TX_OFFLOAD_QINQ_INSERT); 6151 ports[port_id].tx_vlan_id = 0; 6152 ports[port_id].tx_vlan_id_outer = 0; 6153 } 6154 6155 void 6156 tx_vlan_pvid_set(portid_t port_id, uint16_t vlan_id, int on) 6157 { 6158 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6159 return; 6160 6161 rte_eth_dev_set_vlan_pvid(port_id, vlan_id, on); 6162 } 6163 6164 void 6165 set_qmap(portid_t port_id, uint8_t is_rx, uint16_t queue_id, uint8_t map_value) 6166 { 6167 int ret; 6168 6169 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6170 return; 6171 6172 if (is_rx ? (rx_queue_id_is_invalid(queue_id)) : (tx_queue_id_is_invalid(queue_id))) 6173 return; 6174 6175 if (map_value >= RTE_ETHDEV_QUEUE_STAT_CNTRS) { 6176 fprintf(stderr, "map_value not in required range 0..%d\n", 6177 RTE_ETHDEV_QUEUE_STAT_CNTRS - 1); 6178 return; 6179 } 6180 6181 if (!is_rx) { /* tx */ 6182 ret = rte_eth_dev_set_tx_queue_stats_mapping(port_id, queue_id, 6183 map_value); 6184 if (ret) { 6185 fprintf(stderr, 6186 "failed to set tx queue stats mapping.\n"); 6187 return; 6188 } 6189 } else { /* rx */ 6190 ret = rte_eth_dev_set_rx_queue_stats_mapping(port_id, queue_id, 6191 map_value); 6192 if (ret) { 6193 fprintf(stderr, 6194 "failed to set rx queue stats mapping.\n"); 6195 return; 6196 } 6197 } 6198 } 6199 6200 void 6201 set_xstats_hide_zero(uint8_t on_off) 6202 { 6203 xstats_hide_zero = on_off; 6204 } 6205 6206 void 6207 set_record_core_cycles(uint8_t on_off) 6208 { 6209 record_core_cycles = on_off; 6210 } 6211 6212 void 6213 set_record_burst_stats(uint8_t on_off) 6214 { 6215 record_burst_stats = on_off; 6216 } 6217 6218 uint16_t 6219 str_to_flowtype(const char *string) 6220 { 6221 uint8_t i; 6222 6223 for (i = 0; i < RTE_DIM(flowtype_str_table); i++) { 6224 if (!strcmp(flowtype_str_table[i].str, string)) 6225 return flowtype_str_table[i].ftype; 6226 } 6227 6228 if (isdigit(string[0])) { 6229 int val = atoi(string); 6230 if (val > 0 && val < 64) 6231 return (uint16_t)val; 6232 } 6233 6234 return RTE_ETH_FLOW_UNKNOWN; 6235 } 6236 6237 const char* 6238 flowtype_to_str(uint16_t flow_type) 6239 { 6240 uint8_t i; 6241 6242 for (i = 0; i < RTE_DIM(flowtype_str_table); i++) { 6243 if (flowtype_str_table[i].ftype == flow_type) 6244 return flowtype_str_table[i].str; 6245 } 6246 6247 return NULL; 6248 } 6249 6250 #if defined(RTE_NET_I40E) || defined(RTE_NET_IXGBE) 6251 6252 static inline void 6253 print_fdir_flex_payload(struct rte_eth_fdir_flex_conf *flex_conf, uint32_t num) 6254 { 6255 struct rte_eth_flex_payload_cfg *cfg; 6256 uint32_t i, j; 6257 6258 for (i = 0; i < flex_conf->nb_payloads; i++) { 6259 cfg = &flex_conf->flex_set[i]; 6260 if (cfg->type == RTE_ETH_RAW_PAYLOAD) 6261 printf("\n RAW: "); 6262 else if (cfg->type == RTE_ETH_L2_PAYLOAD) 6263 printf("\n L2_PAYLOAD: "); 6264 else if (cfg->type == RTE_ETH_L3_PAYLOAD) 6265 printf("\n L3_PAYLOAD: "); 6266 else if (cfg->type == RTE_ETH_L4_PAYLOAD) 6267 printf("\n L4_PAYLOAD: "); 6268 else 6269 printf("\n UNKNOWN PAYLOAD(%u): ", cfg->type); 6270 for (j = 0; j < num; j++) 6271 printf(" %-5u", cfg->src_offset[j]); 6272 } 6273 printf("\n"); 6274 } 6275 6276 static inline void 6277 print_fdir_flex_mask(struct rte_eth_fdir_flex_conf *flex_conf, uint32_t num) 6278 { 6279 struct rte_eth_fdir_flex_mask *mask; 6280 uint32_t i, j; 6281 const char *p; 6282 6283 for (i = 0; i < flex_conf->nb_flexmasks; i++) { 6284 mask = &flex_conf->flex_mask[i]; 6285 p = flowtype_to_str(mask->flow_type); 6286 printf("\n %s:\t", p ? p : "unknown"); 6287 for (j = 0; j < num; j++) 6288 printf(" %02x", mask->mask[j]); 6289 } 6290 printf("\n"); 6291 } 6292 6293 static inline void 6294 print_fdir_flow_type(uint32_t flow_types_mask) 6295 { 6296 int i; 6297 const char *p; 6298 6299 for (i = RTE_ETH_FLOW_UNKNOWN; i < RTE_ETH_FLOW_MAX; i++) { 6300 if (!(flow_types_mask & (1 << i))) 6301 continue; 6302 p = flowtype_to_str(i); 6303 if (p) 6304 printf(" %s", p); 6305 else 6306 printf(" unknown"); 6307 } 6308 printf("\n"); 6309 } 6310 6311 static int 6312 get_fdir_info(portid_t port_id, struct rte_eth_fdir_info *fdir_info, 6313 struct rte_eth_fdir_stats *fdir_stat) 6314 { 6315 int ret = -ENOTSUP; 6316 6317 #ifdef RTE_NET_I40E 6318 if (ret == -ENOTSUP) { 6319 ret = rte_pmd_i40e_get_fdir_info(port_id, fdir_info); 6320 if (!ret) 6321 ret = rte_pmd_i40e_get_fdir_stats(port_id, fdir_stat); 6322 } 6323 #endif 6324 #ifdef RTE_NET_IXGBE 6325 if (ret == -ENOTSUP) { 6326 ret = rte_pmd_ixgbe_get_fdir_info(port_id, fdir_info); 6327 if (!ret) 6328 ret = rte_pmd_ixgbe_get_fdir_stats(port_id, fdir_stat); 6329 } 6330 #endif 6331 switch (ret) { 6332 case 0: 6333 break; 6334 case -ENOTSUP: 6335 fprintf(stderr, "\n FDIR is not supported on port %-2d\n", 6336 port_id); 6337 break; 6338 default: 6339 fprintf(stderr, "programming error: (%s)\n", strerror(-ret)); 6340 break; 6341 } 6342 return ret; 6343 } 6344 6345 void 6346 fdir_get_infos(portid_t port_id) 6347 { 6348 struct rte_eth_fdir_stats fdir_stat; 6349 struct rte_eth_fdir_info fdir_info; 6350 6351 static const char *fdir_stats_border = "########################"; 6352 6353 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6354 return; 6355 6356 memset(&fdir_info, 0, sizeof(fdir_info)); 6357 memset(&fdir_stat, 0, sizeof(fdir_stat)); 6358 if (get_fdir_info(port_id, &fdir_info, &fdir_stat)) 6359 return; 6360 6361 printf("\n %s FDIR infos for port %-2d %s\n", 6362 fdir_stats_border, port_id, fdir_stats_border); 6363 printf(" MODE: "); 6364 if (fdir_info.mode == RTE_FDIR_MODE_PERFECT) 6365 printf(" PERFECT\n"); 6366 else if (fdir_info.mode == RTE_FDIR_MODE_PERFECT_MAC_VLAN) 6367 printf(" PERFECT-MAC-VLAN\n"); 6368 else if (fdir_info.mode == RTE_FDIR_MODE_PERFECT_TUNNEL) 6369 printf(" PERFECT-TUNNEL\n"); 6370 else if (fdir_info.mode == RTE_FDIR_MODE_SIGNATURE) 6371 printf(" SIGNATURE\n"); 6372 else 6373 printf(" DISABLE\n"); 6374 if (fdir_info.mode != RTE_FDIR_MODE_PERFECT_MAC_VLAN 6375 && fdir_info.mode != RTE_FDIR_MODE_PERFECT_TUNNEL) { 6376 printf(" SUPPORTED FLOW TYPE: "); 6377 print_fdir_flow_type(fdir_info.flow_types_mask[0]); 6378 } 6379 printf(" FLEX PAYLOAD INFO:\n"); 6380 printf(" max_len: %-10"PRIu32" payload_limit: %-10"PRIu32"\n" 6381 " payload_unit: %-10"PRIu32" payload_seg: %-10"PRIu32"\n" 6382 " bitmask_unit: %-10"PRIu32" bitmask_num: %-10"PRIu32"\n", 6383 fdir_info.max_flexpayload, fdir_info.flex_payload_limit, 6384 fdir_info.flex_payload_unit, 6385 fdir_info.max_flex_payload_segment_num, 6386 fdir_info.flex_bitmask_unit, fdir_info.max_flex_bitmask_num); 6387 if (fdir_info.flex_conf.nb_payloads > 0) { 6388 printf(" FLEX PAYLOAD SRC OFFSET:"); 6389 print_fdir_flex_payload(&fdir_info.flex_conf, fdir_info.max_flexpayload); 6390 } 6391 if (fdir_info.flex_conf.nb_flexmasks > 0) { 6392 printf(" FLEX MASK CFG:"); 6393 print_fdir_flex_mask(&fdir_info.flex_conf, fdir_info.max_flexpayload); 6394 } 6395 printf(" guarant_count: %-10"PRIu32" best_count: %"PRIu32"\n", 6396 fdir_stat.guarant_cnt, fdir_stat.best_cnt); 6397 printf(" guarant_space: %-10"PRIu32" best_space: %"PRIu32"\n", 6398 fdir_info.guarant_spc, fdir_info.best_spc); 6399 printf(" collision: %-10"PRIu32" free: %"PRIu32"\n" 6400 " maxhash: %-10"PRIu32" maxlen: %"PRIu32"\n" 6401 " add: %-10"PRIu64" remove: %"PRIu64"\n" 6402 " f_add: %-10"PRIu64" f_remove: %"PRIu64"\n", 6403 fdir_stat.collision, fdir_stat.free, 6404 fdir_stat.maxhash, fdir_stat.maxlen, 6405 fdir_stat.add, fdir_stat.remove, 6406 fdir_stat.f_add, fdir_stat.f_remove); 6407 printf(" %s############################%s\n", 6408 fdir_stats_border, fdir_stats_border); 6409 } 6410 6411 #endif /* RTE_NET_I40E || RTE_NET_IXGBE */ 6412 6413 void 6414 set_vf_traffic(portid_t port_id, uint8_t is_rx, uint16_t vf, uint8_t on) 6415 { 6416 #ifdef RTE_NET_IXGBE 6417 int diag; 6418 6419 if (is_rx) 6420 diag = rte_pmd_ixgbe_set_vf_rx(port_id, vf, on); 6421 else 6422 diag = rte_pmd_ixgbe_set_vf_tx(port_id, vf, on); 6423 6424 if (diag == 0) 6425 return; 6426 fprintf(stderr, 6427 "rte_pmd_ixgbe_set_vf_%s for port_id=%d failed diag=%d\n", 6428 is_rx ? "rx" : "tx", port_id, diag); 6429 return; 6430 #endif 6431 fprintf(stderr, "VF %s setting not supported for port %d\n", 6432 is_rx ? "Rx" : "Tx", port_id); 6433 RTE_SET_USED(vf); 6434 RTE_SET_USED(on); 6435 } 6436 6437 int 6438 set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint32_t rate) 6439 { 6440 int diag; 6441 struct rte_eth_link link; 6442 int ret; 6443 6444 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6445 return 1; 6446 ret = eth_link_get_nowait_print_err(port_id, &link); 6447 if (ret < 0) 6448 return 1; 6449 if (link.link_speed != RTE_ETH_SPEED_NUM_UNKNOWN && 6450 rate > link.link_speed) { 6451 fprintf(stderr, 6452 "Invalid rate value:%u bigger than link speed: %u\n", 6453 rate, link.link_speed); 6454 return 1; 6455 } 6456 diag = rte_eth_set_queue_rate_limit(port_id, queue_idx, rate); 6457 if (diag == 0) 6458 return diag; 6459 fprintf(stderr, 6460 "rte_eth_set_queue_rate_limit for port_id=%d failed diag=%d\n", 6461 port_id, diag); 6462 return diag; 6463 } 6464 6465 int 6466 set_vf_rate_limit(portid_t port_id, uint16_t vf, uint32_t rate, uint64_t q_msk) 6467 { 6468 int diag = -ENOTSUP; 6469 6470 RTE_SET_USED(vf); 6471 RTE_SET_USED(rate); 6472 RTE_SET_USED(q_msk); 6473 6474 #ifdef RTE_NET_IXGBE 6475 if (diag == -ENOTSUP) 6476 diag = rte_pmd_ixgbe_set_vf_rate_limit(port_id, vf, rate, 6477 q_msk); 6478 #endif 6479 #ifdef RTE_NET_BNXT 6480 if (diag == -ENOTSUP) 6481 diag = rte_pmd_bnxt_set_vf_rate_limit(port_id, vf, rate, q_msk); 6482 #endif 6483 if (diag == 0) 6484 return diag; 6485 6486 fprintf(stderr, 6487 "%s for port_id=%d failed diag=%d\n", 6488 __func__, port_id, diag); 6489 return diag; 6490 } 6491 6492 int 6493 set_rxq_avail_thresh(portid_t port_id, uint16_t queue_id, uint8_t avail_thresh) 6494 { 6495 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6496 return -EINVAL; 6497 6498 return rte_eth_rx_avail_thresh_set(port_id, queue_id, avail_thresh); 6499 } 6500 6501 /* 6502 * Functions to manage the set of filtered Multicast MAC addresses. 6503 * 6504 * A pool of filtered multicast MAC addresses is associated with each port. 6505 * The pool is allocated in chunks of MCAST_POOL_INC multicast addresses. 6506 * The address of the pool and the number of valid multicast MAC addresses 6507 * recorded in the pool are stored in the fields "mc_addr_pool" and 6508 * "mc_addr_nb" of the "rte_port" data structure. 6509 * 6510 * The function "rte_eth_dev_set_mc_addr_list" of the PMDs API imposes 6511 * to be supplied a contiguous array of multicast MAC addresses. 6512 * To comply with this constraint, the set of multicast addresses recorded 6513 * into the pool are systematically compacted at the beginning of the pool. 6514 * Hence, when a multicast address is removed from the pool, all following 6515 * addresses, if any, are copied back to keep the set contiguous. 6516 */ 6517 #define MCAST_POOL_INC 32 6518 6519 static int 6520 mcast_addr_pool_extend(struct rte_port *port) 6521 { 6522 struct rte_ether_addr *mc_pool; 6523 size_t mc_pool_size; 6524 6525 /* 6526 * If a free entry is available at the end of the pool, just 6527 * increment the number of recorded multicast addresses. 6528 */ 6529 if ((port->mc_addr_nb % MCAST_POOL_INC) != 0) { 6530 port->mc_addr_nb++; 6531 return 0; 6532 } 6533 6534 /* 6535 * [re]allocate a pool with MCAST_POOL_INC more entries. 6536 * The previous test guarantees that port->mc_addr_nb is a multiple 6537 * of MCAST_POOL_INC. 6538 */ 6539 mc_pool_size = sizeof(struct rte_ether_addr) * (port->mc_addr_nb + 6540 MCAST_POOL_INC); 6541 mc_pool = (struct rte_ether_addr *) realloc(port->mc_addr_pool, 6542 mc_pool_size); 6543 if (mc_pool == NULL) { 6544 fprintf(stderr, 6545 "allocation of pool of %u multicast addresses failed\n", 6546 port->mc_addr_nb + MCAST_POOL_INC); 6547 return -ENOMEM; 6548 } 6549 6550 port->mc_addr_pool = mc_pool; 6551 port->mc_addr_nb++; 6552 return 0; 6553 6554 } 6555 6556 static void 6557 mcast_addr_pool_append(struct rte_port *port, struct rte_ether_addr *mc_addr) 6558 { 6559 if (mcast_addr_pool_extend(port) != 0) 6560 return; 6561 rte_ether_addr_copy(mc_addr, &port->mc_addr_pool[port->mc_addr_nb - 1]); 6562 } 6563 6564 static void 6565 mcast_addr_pool_remove(struct rte_port *port, uint32_t addr_idx) 6566 { 6567 port->mc_addr_nb--; 6568 if (addr_idx == port->mc_addr_nb) { 6569 /* No need to recompact the set of multicast addresses. */ 6570 if (port->mc_addr_nb == 0) { 6571 /* free the pool of multicast addresses. */ 6572 free(port->mc_addr_pool); 6573 port->mc_addr_pool = NULL; 6574 } 6575 return; 6576 } 6577 memmove(&port->mc_addr_pool[addr_idx], 6578 &port->mc_addr_pool[addr_idx + 1], 6579 sizeof(struct rte_ether_addr) * (port->mc_addr_nb - addr_idx)); 6580 } 6581 6582 int 6583 mcast_addr_pool_destroy(portid_t port_id) 6584 { 6585 struct rte_port *port; 6586 6587 if (port_id_is_invalid(port_id, ENABLED_WARN) || 6588 port_id == (portid_t)RTE_PORT_ALL) 6589 return -EINVAL; 6590 port = &ports[port_id]; 6591 6592 if (port->mc_addr_nb != 0) { 6593 /* free the pool of multicast addresses. */ 6594 free(port->mc_addr_pool); 6595 port->mc_addr_pool = NULL; 6596 port->mc_addr_nb = 0; 6597 } 6598 return 0; 6599 } 6600 6601 static int 6602 eth_port_multicast_addr_list_set(portid_t port_id) 6603 { 6604 struct rte_port *port; 6605 int diag; 6606 6607 port = &ports[port_id]; 6608 diag = rte_eth_dev_set_mc_addr_list(port_id, port->mc_addr_pool, 6609 port->mc_addr_nb); 6610 if (diag < 0) 6611 fprintf(stderr, 6612 "rte_eth_dev_set_mc_addr_list(port=%d, nb=%u) failed. diag=%d\n", 6613 port_id, port->mc_addr_nb, diag); 6614 6615 return diag; 6616 } 6617 6618 void 6619 mcast_addr_add(portid_t port_id, struct rte_ether_addr *mc_addr) 6620 { 6621 struct rte_port *port; 6622 uint32_t i; 6623 6624 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6625 return; 6626 6627 port = &ports[port_id]; 6628 6629 /* 6630 * Check that the added multicast MAC address is not already recorded 6631 * in the pool of multicast addresses. 6632 */ 6633 for (i = 0; i < port->mc_addr_nb; i++) { 6634 if (rte_is_same_ether_addr(mc_addr, &port->mc_addr_pool[i])) { 6635 fprintf(stderr, 6636 "multicast address already filtered by port\n"); 6637 return; 6638 } 6639 } 6640 6641 mcast_addr_pool_append(port, mc_addr); 6642 if (eth_port_multicast_addr_list_set(port_id) < 0) 6643 /* Rollback on failure, remove the address from the pool */ 6644 mcast_addr_pool_remove(port, i); 6645 } 6646 6647 void 6648 mcast_addr_remove(portid_t port_id, struct rte_ether_addr *mc_addr) 6649 { 6650 struct rte_port *port; 6651 uint32_t i; 6652 6653 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6654 return; 6655 6656 port = &ports[port_id]; 6657 6658 /* 6659 * Search the pool of multicast MAC addresses for the removed address. 6660 */ 6661 for (i = 0; i < port->mc_addr_nb; i++) { 6662 if (rte_is_same_ether_addr(mc_addr, &port->mc_addr_pool[i])) 6663 break; 6664 } 6665 if (i == port->mc_addr_nb) { 6666 fprintf(stderr, "multicast address not filtered by port %d\n", 6667 port_id); 6668 return; 6669 } 6670 6671 mcast_addr_pool_remove(port, i); 6672 if (eth_port_multicast_addr_list_set(port_id) < 0) 6673 /* Rollback on failure, add the address back into the pool */ 6674 mcast_addr_pool_append(port, mc_addr); 6675 } 6676 6677 void 6678 port_dcb_info_display(portid_t port_id) 6679 { 6680 struct rte_eth_dcb_info dcb_info; 6681 uint16_t i; 6682 int ret; 6683 static const char *border = "================"; 6684 6685 if (port_id_is_invalid(port_id, ENABLED_WARN)) 6686 return; 6687 6688 ret = rte_eth_dev_get_dcb_info(port_id, &dcb_info); 6689 if (ret) { 6690 fprintf(stderr, "\n Failed to get dcb infos on port %-2d\n", 6691 port_id); 6692 return; 6693 } 6694 printf("\n %s DCB infos for port %-2d %s\n", border, port_id, border); 6695 printf(" TC NUMBER: %d\n", dcb_info.nb_tcs); 6696 printf("\n TC : "); 6697 for (i = 0; i < dcb_info.nb_tcs; i++) 6698 printf("\t%4d", i); 6699 printf("\n Priority : "); 6700 for (i = 0; i < dcb_info.nb_tcs; i++) 6701 printf("\t%4d", dcb_info.prio_tc[i]); 6702 printf("\n BW percent :"); 6703 for (i = 0; i < dcb_info.nb_tcs; i++) 6704 printf("\t%4d%%", dcb_info.tc_bws[i]); 6705 printf("\n RXQ base : "); 6706 for (i = 0; i < dcb_info.nb_tcs; i++) 6707 printf("\t%4d", dcb_info.tc_queue.tc_rxq[0][i].base); 6708 printf("\n RXQ number :"); 6709 for (i = 0; i < dcb_info.nb_tcs; i++) 6710 printf("\t%4d", dcb_info.tc_queue.tc_rxq[0][i].nb_queue); 6711 printf("\n TXQ base : "); 6712 for (i = 0; i < dcb_info.nb_tcs; i++) 6713 printf("\t%4d", dcb_info.tc_queue.tc_txq[0][i].base); 6714 printf("\n TXQ number :"); 6715 for (i = 0; i < dcb_info.nb_tcs; i++) 6716 printf("\t%4d", dcb_info.tc_queue.tc_txq[0][i].nb_queue); 6717 printf("\n"); 6718 } 6719 6720 uint8_t * 6721 open_file(const char *file_path, uint32_t *size) 6722 { 6723 int fd = open(file_path, O_RDONLY); 6724 off_t pkg_size; 6725 uint8_t *buf = NULL; 6726 int ret = 0; 6727 struct stat st_buf; 6728 6729 if (size) 6730 *size = 0; 6731 6732 if (fd == -1) { 6733 fprintf(stderr, "%s: Failed to open %s\n", __func__, file_path); 6734 return buf; 6735 } 6736 6737 if ((fstat(fd, &st_buf) != 0) || (!S_ISREG(st_buf.st_mode))) { 6738 close(fd); 6739 fprintf(stderr, "%s: File operations failed\n", __func__); 6740 return buf; 6741 } 6742 6743 pkg_size = st_buf.st_size; 6744 if (pkg_size < 0) { 6745 close(fd); 6746 fprintf(stderr, "%s: File operations failed\n", __func__); 6747 return buf; 6748 } 6749 6750 buf = (uint8_t *)malloc(pkg_size); 6751 if (!buf) { 6752 close(fd); 6753 fprintf(stderr, "%s: Failed to malloc memory\n", __func__); 6754 return buf; 6755 } 6756 6757 ret = read(fd, buf, pkg_size); 6758 if (ret < 0) { 6759 close(fd); 6760 fprintf(stderr, "%s: File read operation failed\n", __func__); 6761 close_file(buf); 6762 return NULL; 6763 } 6764 6765 if (size) 6766 *size = pkg_size; 6767 6768 close(fd); 6769 6770 return buf; 6771 } 6772 6773 int 6774 save_file(const char *file_path, uint8_t *buf, uint32_t size) 6775 { 6776 FILE *fh = fopen(file_path, "wb"); 6777 6778 if (fh == NULL) { 6779 fprintf(stderr, "%s: Failed to open %s\n", __func__, file_path); 6780 return -1; 6781 } 6782 6783 if (fwrite(buf, 1, size, fh) != size) { 6784 fclose(fh); 6785 fprintf(stderr, "%s: File write operation failed\n", __func__); 6786 return -1; 6787 } 6788 6789 fclose(fh); 6790 6791 return 0; 6792 } 6793 6794 int 6795 close_file(uint8_t *buf) 6796 { 6797 if (buf) { 6798 free((void *)buf); 6799 return 0; 6800 } 6801 6802 return -1; 6803 } 6804 6805 void 6806 show_macs(portid_t port_id) 6807 { 6808 char buf[RTE_ETHER_ADDR_FMT_SIZE]; 6809 struct rte_eth_dev_info dev_info; 6810 int32_t i, rc, num_macs = 0; 6811 6812 if (eth_dev_info_get_print_err(port_id, &dev_info)) 6813 return; 6814 6815 struct rte_ether_addr addr[dev_info.max_mac_addrs]; 6816 rc = rte_eth_macaddrs_get(port_id, addr, dev_info.max_mac_addrs); 6817 if (rc < 0) 6818 return; 6819 6820 for (i = 0; i < rc; i++) { 6821 6822 /* skip zero address */ 6823 if (rte_is_zero_ether_addr(&addr[i])) 6824 continue; 6825 6826 num_macs++; 6827 } 6828 6829 printf("Number of MAC address added: %d\n", num_macs); 6830 6831 for (i = 0; i < rc; i++) { 6832 6833 /* skip zero address */ 6834 if (rte_is_zero_ether_addr(&addr[i])) 6835 continue; 6836 6837 rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, &addr[i]); 6838 printf(" %s\n", buf); 6839 } 6840 } 6841 6842 void 6843 show_mcast_macs(portid_t port_id) 6844 { 6845 char buf[RTE_ETHER_ADDR_FMT_SIZE]; 6846 struct rte_ether_addr *addr; 6847 struct rte_port *port; 6848 uint32_t i; 6849 6850 port = &ports[port_id]; 6851 6852 printf("Number of Multicast MAC address added: %d\n", port->mc_addr_nb); 6853 6854 for (i = 0; i < port->mc_addr_nb; i++) { 6855 addr = &port->mc_addr_pool[i]; 6856 6857 rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE, addr); 6858 printf(" %s\n", buf); 6859 } 6860 } 6861