#include "testpmd.h"
+#define ETHDEV_FWVERS_LEN 32
+
+#ifdef CLOCK_MONOTONIC_RAW /* Defined in glibc bits/time.h */
+#define CLOCK_TYPE_ID CLOCK_MONOTONIC_RAW
+#else
+#define CLOCK_TYPE_ID CLOCK_MONOTONIC
+#endif
+
+#define NS_PER_SEC 1E9
+
static char *flowtype_to_str(uint16_t flow_type);
static const struct {
};
const struct rss_type_info rss_type_table[] = {
- { "all", ETH_RSS_IP | ETH_RSS_TCP |
- ETH_RSS_UDP | ETH_RSS_SCTP |
- ETH_RSS_L2_PAYLOAD },
+ { "all", ETH_RSS_ETH | ETH_RSS_VLAN | ETH_RSS_IP | ETH_RSS_TCP |
+ ETH_RSS_UDP | ETH_RSS_SCTP | ETH_RSS_L2_PAYLOAD |
+ ETH_RSS_L2TPV3 | ETH_RSS_ESP | ETH_RSS_AH | ETH_RSS_PFCP |
+ ETH_RSS_GTPU},
{ "none", 0 },
+ { "eth", ETH_RSS_ETH },
+ { "l2-src-only", ETH_RSS_L2_SRC_ONLY },
+ { "l2-dst-only", ETH_RSS_L2_DST_ONLY },
+ { "vlan", ETH_RSS_VLAN },
+ { "s-vlan", ETH_RSS_S_VLAN },
+ { "c-vlan", ETH_RSS_C_VLAN },
{ "ipv4", ETH_RSS_IPV4 },
{ "ipv4-frag", ETH_RSS_FRAG_IPV4 },
{ "ipv4-tcp", ETH_RSS_NONFRAG_IPV4_TCP },
{ "l3-dst-only", ETH_RSS_L3_DST_ONLY },
{ "l4-src-only", ETH_RSS_L4_SRC_ONLY },
{ "l4-dst-only", ETH_RSS_L4_DST_ONLY },
+ { "esp", ETH_RSS_ESP },
+ { "ah", ETH_RSS_AH },
+ { "l2tpv3", ETH_RSS_L2TPV3 },
+ { "pfcp", ETH_RSS_PFCP },
+ { "pppoe", ETH_RSS_PPPOE },
+ { "gtpu", ETH_RSS_GTPU },
{ NULL, 0 },
};
static uint64_t prev_pkts_tx[RTE_MAX_ETHPORTS];
static uint64_t prev_bytes_rx[RTE_MAX_ETHPORTS];
static uint64_t prev_bytes_tx[RTE_MAX_ETHPORTS];
- static uint64_t prev_cycles[RTE_MAX_ETHPORTS];
+ static uint64_t prev_ns[RTE_MAX_ETHPORTS];
+ struct timespec cur_time;
uint64_t diff_pkts_rx, diff_pkts_tx, diff_bytes_rx, diff_bytes_tx,
- diff_cycles;
+ diff_ns;
uint64_t mpps_rx, mpps_tx, mbps_rx, mbps_tx;
struct rte_eth_stats stats;
struct rte_port *port = &ports[port_id];
}
}
- diff_cycles = prev_cycles[port_id];
- prev_cycles[port_id] = rte_rdtsc();
- if (diff_cycles > 0)
- diff_cycles = prev_cycles[port_id] - diff_cycles;
+ diff_ns = 0;
+ if (clock_gettime(CLOCK_TYPE_ID, &cur_time) == 0) {
+ uint64_t ns;
+
+ ns = cur_time.tv_sec * NS_PER_SEC;
+ ns += cur_time.tv_nsec;
+
+ if (prev_ns[port_id] != 0)
+ diff_ns = ns - prev_ns[port_id];
+ prev_ns[port_id] = ns;
+ }
diff_pkts_rx = (stats.ipackets > prev_pkts_rx[port_id]) ?
(stats.ipackets - prev_pkts_rx[port_id]) : 0;
(stats.opackets - prev_pkts_tx[port_id]) : 0;
prev_pkts_rx[port_id] = stats.ipackets;
prev_pkts_tx[port_id] = stats.opackets;
- mpps_rx = diff_cycles > 0 ?
- diff_pkts_rx * rte_get_tsc_hz() / diff_cycles : 0;
- mpps_tx = diff_cycles > 0 ?
- diff_pkts_tx * rte_get_tsc_hz() / diff_cycles : 0;
+ mpps_rx = diff_ns > 0 ?
+ (double)diff_pkts_rx / diff_ns * NS_PER_SEC : 0;
+ mpps_tx = diff_ns > 0 ?
+ (double)diff_pkts_tx / diff_ns * NS_PER_SEC : 0;
diff_bytes_rx = (stats.ibytes > prev_bytes_rx[port_id]) ?
(stats.ibytes - prev_bytes_rx[port_id]) : 0;
(stats.obytes - prev_bytes_tx[port_id]) : 0;
prev_bytes_rx[port_id] = stats.ibytes;
prev_bytes_tx[port_id] = stats.obytes;
- mbps_rx = diff_cycles > 0 ?
- diff_bytes_rx * rte_get_tsc_hz() / diff_cycles : 0;
- mbps_tx = diff_cycles > 0 ?
- diff_bytes_tx * rte_get_tsc_hz() / diff_cycles : 0;
+ mbps_rx = diff_ns > 0 ?
+ (double)diff_bytes_rx / diff_ns * NS_PER_SEC : 0;
+ mbps_tx = diff_ns > 0 ?
+ (double)diff_bytes_tx / diff_ns * NS_PER_SEC : 0;
printf("\n Throughput (since last show)\n");
printf(" Rx-pps: %12"PRIu64" Rx-bps: %12"PRIu64"\n Tx-pps: %12"
void
nic_stats_clear(portid_t port_id)
{
+ int ret;
+
if (port_id_is_invalid(port_id, ENABLED_WARN)) {
print_valid_ports();
return;
}
- rte_eth_stats_reset(port_id);
+
+ ret = rte_eth_stats_reset(port_id);
+ if (ret != 0) {
+ printf("%s: Error: failed to reset stats (port %u): %s",
+ __func__, port_id, strerror(-ret));
+ return;
+ }
+
+ ret = rte_eth_stats_get(port_id, &ports[port_id].stats);
+ if (ret != 0) {
+ if (ret < 0)
+ ret = -ret;
+ printf("%s: Error: failed to get stats (port %u): %s",
+ __func__, port_id, strerror(ret));
+ return;
+ }
printf("\n NIC statistics for port %d cleared\n", port_id);
}
print_valid_ports();
return;
}
+
ret = rte_eth_xstats_reset(port_id);
if (ret != 0) {
printf("%s: Error: failed to reset xstats (port %u): %s",
+ __func__, port_id, strerror(-ret));
+ return;
+ }
+
+ ret = rte_eth_stats_get(port_id, &ports[port_id].stats);
+ if (ret != 0) {
+ if (ret < 0)
+ ret = -ret;
+ printf("%s: Error: failed to get stats (port %u): %s",
__func__, port_id, strerror(ret));
+ return;
}
}
uint16_t mtu;
char name[RTE_ETH_NAME_MAX_LEN];
int ret;
+ char fw_version[ETHDEV_FWVERS_LEN];
if (port_id_is_invalid(port_id, ENABLED_WARN)) {
print_valid_ports();
rte_eth_dev_get_name_by_port(port_id, name);
printf("\nDevice name: %s", name);
printf("\nDriver name: %s", dev_info.driver_name);
+
+ if (rte_eth_dev_fw_version_get(port_id, fw_version,
+ ETHDEV_FWVERS_LEN) == 0)
+ printf("\nFirmware-version: %s", fw_version);
+ else
+ printf("\nFirmware-version: %s", "not available");
+
if (dev_info.device->devargs && dev_info.device->devargs->args)
printf("\nDevargs: %s", dev_info.device->devargs->args);
printf("\nConnect to socket: %u", port->socket_id);
port_mtu_set(portid_t port_id, uint16_t mtu)
{
int diag;
+ struct rte_port *rte_port = &ports[port_id];
struct rte_eth_dev_info dev_info;
+ uint16_t eth_overhead;
int ret;
if (port_id_is_invalid(port_id, ENABLED_WARN))
return;
}
diag = rte_eth_dev_set_mtu(port_id, mtu);
- if (diag == 0)
- return;
- printf("Set MTU failed. diag=%d\n", diag);
+ if (diag)
+ printf("Set MTU failed. diag=%d\n", diag);
+ else if (dev_info.rx_offload_capa & DEV_RX_OFFLOAD_JUMBO_FRAME) {
+ /*
+ * Ether overhead in driver is equal to the difference of
+ * max_rx_pktlen and max_mtu in rte_eth_dev_info when the
+ * device supports jumbo frame.
+ */
+ eth_overhead = dev_info.max_rx_pktlen - dev_info.max_mtu;
+ if (mtu > RTE_ETHER_MAX_LEN - eth_overhead) {
+ rte_port->dev_conf.rxmode.offloads |=
+ DEV_RX_OFFLOAD_JUMBO_FRAME;
+ rte_port->dev_conf.rxmode.max_rx_pkt_len =
+ mtu + eth_overhead;
+ } else
+ rte_port->dev_conf.rxmode.offloads &=
+ ~DEV_RX_OFFLOAD_JUMBO_FRAME;
+ }
}
/* Generic flow management functions. */
return 0;
}
+/** Update age action context by port_flow pointer. */
+void
+update_age_action_context(const struct rte_flow_action *actions,
+ struct port_flow *pf)
+{
+ struct rte_flow_action_age *age = NULL;
+
+ for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+ switch (actions->type) {
+ case RTE_FLOW_ACTION_TYPE_AGE:
+ age = (struct rte_flow_action_age *)
+ (uintptr_t)actions->conf;
+ age->context = pf;
+ return;
+ default:
+ break;
+ }
+ }
+}
+
/** Create flow rule. */
int
port_flow_create(portid_t port_id,
struct rte_flow *flow;
struct rte_port *port;
struct port_flow *pf;
- uint32_t id;
+ uint32_t id = 0;
struct rte_flow_error error;
- /* Poisoning to make sure PMDs update it in case of error. */
- memset(&error, 0x22, sizeof(error));
- flow = rte_flow_create(port_id, attr, pattern, actions, &error);
- if (!flow)
- return port_flow_complain(&error);
port = &ports[port_id];
if (port->flow_list) {
if (port->flow_list->id == UINT32_MAX) {
printf("Highest rule ID is already assigned, delete"
" it first");
- rte_flow_destroy(port_id, flow, NULL);
return -ENOMEM;
}
id = port->flow_list->id + 1;
- } else
- id = 0;
+ }
pf = port_flow_new(attr, pattern, actions, &error);
- if (!pf) {
- rte_flow_destroy(port_id, flow, NULL);
+ if (!pf)
+ return port_flow_complain(&error);
+ update_age_action_context(actions, pf);
+ /* Poisoning to make sure PMDs update it in case of error. */
+ memset(&error, 0x22, sizeof(error));
+ flow = rte_flow_create(port_id, attr, pattern, actions, &error);
+ if (!flow) {
+ free(pf);
return port_flow_complain(&error);
}
pf->next = port->flow_list;
return 0;
}
+/** List simply and destroy all aged flows. */
+void
+port_flow_aged(portid_t port_id, uint8_t destroy)
+{
+ void **contexts;
+ int nb_context, total = 0, idx;
+ struct rte_flow_error error;
+ struct port_flow *pf;
+
+ if (port_id_is_invalid(port_id, ENABLED_WARN) ||
+ port_id == (portid_t)RTE_PORT_ALL)
+ return;
+ total = rte_flow_get_aged_flows(port_id, NULL, 0, &error);
+ printf("Port %u total aged flows: %d\n", port_id, total);
+ if (total < 0) {
+ port_flow_complain(&error);
+ return;
+ }
+ if (total == 0)
+ return;
+ contexts = malloc(sizeof(void *) * total);
+ if (contexts == NULL) {
+ printf("Cannot allocate contexts for aged flow\n");
+ return;
+ }
+ printf("ID\tGroup\tPrio\tAttr\n");
+ nb_context = rte_flow_get_aged_flows(port_id, contexts, total, &error);
+ if (nb_context != total) {
+ printf("Port:%d get aged flows count(%d) != total(%d)\n",
+ port_id, nb_context, total);
+ free(contexts);
+ return;
+ }
+ for (idx = 0; idx < nb_context; idx++) {
+ pf = (struct port_flow *)contexts[idx];
+ if (!pf) {
+ printf("Error: get Null context in port %u\n", port_id);
+ continue;
+ }
+ printf("%" PRIu32 "\t%" PRIu32 "\t%" PRIu32 "\t%c%c%c\t\n",
+ pf->id,
+ pf->rule.attr->group,
+ pf->rule.attr->priority,
+ pf->rule.attr->ingress ? 'i' : '-',
+ pf->rule.attr->egress ? 'e' : '-',
+ pf->rule.attr->transfer ? 't' : '-');
+ }
+ if (destroy) {
+ int ret;
+ uint32_t flow_id;
+
+ total = 0;
+ printf("\n");
+ for (idx = 0; idx < nb_context; idx++) {
+ pf = (struct port_flow *)contexts[idx];
+ if (!pf)
+ continue;
+ flow_id = pf->id;
+ ret = port_flow_destroy(port_id, 1, &flow_id);
+ if (!ret)
+ total++;
+ }
+ printf("%d flows be destroyed\n", total);
+ }
+ free(contexts);
+}
+
/** List flow rules. */
void
port_flow_list(portid_t port_id, uint32_t n, const uint32_t group[n])
* If the user wants to use only the ports 1,2 then the input
* is 1,2.
* valid characters are '-' and ','
- * invalid chars like '.' or '#' will result in
- * EAL: Error - exiting with code: 1
- * Cause: Invalid fwd port list
* @param[out] values
* This array will be filled with a list of port IDs
* based on the user input
* 1) Number of elements in the values array
* 2) Maximum value of each element in the values array
* @return
- * -returns total count of parsed port IDs
+ * On success, returns total count of parsed port IDs
+ * On failure, returns 0
*/
static unsigned int
parse_port_list(const char *list, unsigned int *values, unsigned int maxsize)
unsigned int marked[maxsize];
if (list == NULL || values == NULL)
- return -1;
+ return 0;
for (i = 0; i < (int)maxsize; i++)
marked[i] = 0;
* and thereby calculate the total number of
* valid ports
*/
- for (i = 0; i < portcount && valid_port_count < portcount; i++) {
+ for (i = 0; i < portcount && i < RTE_DIM(portindex); i++) {
if (rte_eth_dev_is_valid_port(portindex[i])) {
portindex[valid_port_count] = portindex[i];
valid_port_count++;