aboutsummaryrefslogtreecommitdiffstats
path: root/lib/librte_ethdev
diff options
context:
space:
mode:
Diffstat (limited to 'lib/librte_ethdev')
-rw-r--r--lib/librte_ethdev/Makefile6
-rw-r--r--lib/librte_ethdev/ethdev_private.c121
-rw-r--r--lib/librte_ethdev/ethdev_private.h38
-rw-r--r--lib/librte_ethdev/ethdev_profile.c103
-rw-r--r--lib/librte_ethdev/ethdev_profile.h6
-rw-r--r--lib/librte_ethdev/meson.build8
-rw-r--r--lib/librte_ethdev/rte_class_eth.c173
-rw-r--r--lib/librte_ethdev/rte_ethdev.c463
-rw-r--r--lib/librte_ethdev/rte_ethdev.h183
-rw-r--r--lib/librte_ethdev/rte_ethdev_core.h50
-rw-r--r--lib/librte_ethdev/rte_ethdev_driver.h37
-rw-r--r--lib/librte_ethdev/rte_ethdev_pci.h11
-rw-r--r--lib/librte_ethdev/rte_ethdev_version.map17
-rw-r--r--lib/librte_ethdev/rte_flow.c686
-rw-r--r--lib/librte_ethdev/rte_flow.h484
-rw-r--r--lib/librte_ethdev/rte_tm.h4
16 files changed, 1800 insertions, 590 deletions
diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index 0935a275..3e27ae46 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -12,13 +12,15 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
CFLAGS += -O3
CFLAGS += $(WERROR_FLAGS)
LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs -lrte_cmdline
EXPORT_MAP := rte_ethdev_version.map
-LIBABIVER := 10
+LIBABIVER := 11
+SRCS-y += ethdev_private.c
SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
SRCS-y += rte_flow.c
SRCS-y += rte_tm.c
SRCS-y += rte_mtr.c
diff --git a/lib/librte_ethdev/ethdev_private.c b/lib/librte_ethdev/ethdev_private.c
new file mode 100644
index 00000000..162a502f
--- /dev/null
+++ b/lib/librte_ethdev/ethdev_private.c
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_driver.h"
+#include "ethdev_private.h"
+
+uint16_t
+eth_dev_to_id(const struct rte_eth_dev *dev)
+{
+ if (dev == NULL)
+ return RTE_MAX_ETHPORTS;
+ return dev - rte_eth_devices;
+}
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+ const void *data)
+{
+ struct rte_eth_dev *edev;
+ ptrdiff_t idx;
+
+ /* Avoid Undefined Behaviour */
+ if (start != NULL &&
+ (start < &rte_eth_devices[0] ||
+ start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+ return NULL;
+ if (start != NULL)
+ idx = eth_dev_to_id(start) + 1;
+ else
+ idx = 0;
+ for (; idx < RTE_MAX_ETHPORTS; idx++) {
+ edev = &rte_eth_devices[idx];
+ if (cmp(edev, data) == 0)
+ return edev;
+ }
+ return NULL;
+}
+
+int
+rte_eth_devargs_parse_list(char *str, rte_eth_devargs_callback_t callback,
+ void *data)
+{
+ char *str_start;
+ int state;
+ int result;
+
+ if (*str != '[')
+ /* Single element, not a list */
+ return callback(str, data);
+
+ /* Sanity check, then strip the brackets */
+ str_start = &str[strlen(str) - 1];
+ if (*str_start != ']') {
+ RTE_LOG(ERR, EAL, "(%s): List does not end with ']'\n", str);
+ return -EINVAL;
+ }
+ str++;
+ *str_start = '\0';
+
+ /* Process list elements */
+ state = 0;
+ while (1) {
+ if (state == 0) {
+ if (*str == '\0')
+ break;
+ if (*str != ',') {
+ str_start = str;
+ state = 1;
+ }
+ } else if (state == 1) {
+ if (*str == ',' || *str == '\0') {
+ if (str > str_start) {
+ /* Non-empty string fragment */
+ *str = '\0';
+ result = callback(str_start, data);
+ if (result < 0)
+ return result;
+ }
+ state = 0;
+ }
+ }
+ str++;
+ }
+ return 0;
+}
+
+static int
+rte_eth_devargs_process_range(char *str, uint16_t *list, uint16_t *len_list,
+ const uint16_t max_list)
+{
+ uint16_t lo, hi, val;
+ int result;
+
+ result = sscanf(str, "%hu-%hu", &lo, &hi);
+ if (result == 1) {
+ if (*len_list >= max_list)
+ return -ENOMEM;
+ list[(*len_list)++] = lo;
+ } else if (result == 2) {
+ if (lo >= hi || lo > RTE_MAX_ETHPORTS || hi > RTE_MAX_ETHPORTS)
+ return -EINVAL;
+ for (val = lo; val <= hi; val++) {
+ if (*len_list >= max_list)
+ return -ENOMEM;
+ list[(*len_list)++] = val;
+ }
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+int
+rte_eth_devargs_parse_representor_ports(char *str, void *data)
+{
+ struct rte_eth_devargs *eth_da = data;
+
+ return rte_eth_devargs_process_range(str, eth_da->representor_ports,
+ &eth_da->nb_representor_ports, RTE_MAX_ETHPORTS);
+}
diff --git a/lib/librte_ethdev/ethdev_private.h b/lib/librte_ethdev/ethdev_private.h
new file mode 100644
index 00000000..7b787bf9
--- /dev/null
+++ b/lib/librte_ethdev/ethdev_private.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Convert rte_eth_dev pointer to port id.
+ * NULL will be translated to RTE_MAX_ETHPORTS.
+ */
+uint16_t eth_dev_to_id(const struct rte_eth_dev *dev);
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+ const void *data);
+
+/* Parse devargs value for representor parameter. */
+typedef int (*rte_eth_devargs_callback_t)(char *str, void *data);
+int rte_eth_devargs_parse_list(char *str, rte_eth_devargs_callback_t callback,
+ void *data);
+int rte_eth_devargs_parse_representor_ports(char *str, void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
diff --git a/lib/librte_ethdev/ethdev_profile.c b/lib/librte_ethdev/ethdev_profile.c
index 0d1dcda3..a3c303f6 100644
--- a/lib/librte_ethdev/ethdev_profile.c
+++ b/lib/librte_ethdev/ethdev_profile.c
@@ -1,87 +1,33 @@
/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2017 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
*/
#include "ethdev_profile.h"
/**
- * This conditional block enables RX queues profiling by tracking wasted
- * iterations, i.e. iterations which yielded no RX packets. Profiling is
- * performed using the Instrumentation and Tracing Technology (ITT) API,
- * employed by the Intel (R) VTune (TM) Amplifier.
+ * This conditional block enables Ethernet device profiling with
+ * Intel (R) VTune (TM) Amplifier.
*/
-#ifdef RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS
-
-#include <ittnotify.h>
-
-#define ITT_MAX_NAME_LEN (100)
-
-/**
- * Auxiliary ITT structure belonging to Ethernet device and using to:
- * - track RX queue state to determine whether it is wasting loop iterations
- * - begin or end ITT task using task domain and task name (handle)
- */
-struct itt_profile_rx_data {
- /**
- * ITT domains for each queue.
- */
- __itt_domain *domains[RTE_MAX_QUEUES_PER_PORT];
- /**
- * ITT task names for each queue.
- */
- __itt_string_handle *handles[RTE_MAX_QUEUES_PER_PORT];
- /**
- * Flags indicating the queues state. Possible values:
- * 1 - queue is wasting iterations,
- * 0 - otherwise.
- */
- uint8_t queue_state[RTE_MAX_QUEUES_PER_PORT];
-};
-
-/**
- * The pool of *itt_profile_rx_data* structures.
- */
-struct itt_profile_rx_data itt_rx_data[RTE_MAX_ETHPORTS];
-
+#ifdef RTE_ETHDEV_PROFILE_WITH_VTUNE
/**
- * This callback function manages ITT tasks collection on given port and queue.
- * It must be registered with rte_eth_add_rx_callback() to be called from
- * rte_eth_rx_burst(). To find more comments see rte_rx_callback_fn function
- * type declaration.
+ * Hook callback to trace rte_eth_rx_burst() calls.
*/
-static uint16_t
-collect_itt_rx_burst_cb(uint16_t port_id, uint16_t queue_id,
+uint16_t
+profile_hook_rx_burst_cb(
+ __rte_unused uint16_t port_id, __rte_unused uint16_t queue_id,
__rte_unused struct rte_mbuf *pkts[], uint16_t nb_pkts,
__rte_unused uint16_t max_pkts, __rte_unused void *user_param)
{
- if (unlikely(nb_pkts == 0)) {
- if (!itt_rx_data[port_id].queue_state[queue_id]) {
- __itt_task_begin(
- itt_rx_data[port_id].domains[queue_id],
- __itt_null, __itt_null,
- itt_rx_data[port_id].handles[queue_id]);
- itt_rx_data[port_id].queue_state[queue_id] = 1;
- }
- } else {
- if (unlikely(itt_rx_data[port_id].queue_state[queue_id])) {
- __itt_task_end(
- itt_rx_data[port_id].domains[queue_id]);
- itt_rx_data[port_id].queue_state[queue_id] = 0;
- }
- }
return nb_pkts;
}
/**
- * Initialization of itt_profile_rx_data for a given Ethernet device.
+ * Setting profiling rx callback for a given Ethernet device.
* This function must be invoked when ethernet device is being configured.
- * Result will be stored in the global array *itt_rx_data*.
*
* @param port_id
* The port identifier of the Ethernet device.
- * @param port_name
- * The name of the Ethernet device.
* @param rx_queue_num
* The number of RX queues on specified port.
*
@@ -90,46 +36,27 @@ collect_itt_rx_burst_cb(uint16_t port_id, uint16_t queue_id,
* - On failure, a negative value.
*/
static inline int
-itt_profile_rx_init(uint16_t port_id, char *port_name, uint8_t rx_queue_num)
+vtune_profile_rx_init(uint16_t port_id, uint8_t rx_queue_num)
{
uint16_t q_id;
for (q_id = 0; q_id < rx_queue_num; ++q_id) {
- char domain_name[ITT_MAX_NAME_LEN];
-
- snprintf(domain_name, sizeof(domain_name),
- "RXBurst.WastedIterations.Port_%s.Queue_%d",
- port_name, q_id);
- itt_rx_data[port_id].domains[q_id]
- = __itt_domain_create(domain_name);
-
- char task_name[ITT_MAX_NAME_LEN];
-
- snprintf(task_name, sizeof(task_name),
- "port id: %d; queue id: %d",
- port_id, q_id);
- itt_rx_data[port_id].handles[q_id]
- = __itt_string_handle_create(task_name);
-
- itt_rx_data[port_id].queue_state[q_id] = 0;
-
if (!rte_eth_add_rx_callback(
- port_id, q_id, collect_itt_rx_burst_cb, NULL)) {
+ port_id, q_id, profile_hook_rx_burst_cb, NULL)) {
return -rte_errno;
}
}
return 0;
}
-#endif /* RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS */
+#endif /* RTE_ETHDEV_PROFILE_WITH_VTUNE */
int
-__rte_eth_profile_rx_init(__rte_unused uint16_t port_id,
+__rte_eth_dev_profile_init(__rte_unused uint16_t port_id,
__rte_unused struct rte_eth_dev *dev)
{
-#ifdef RTE_ETHDEV_PROFILE_ITT_WASTED_RX_ITERATIONS
- return itt_profile_rx_init(
- port_id, dev->data->name, dev->data->nb_rx_queues);
+#ifdef RTE_ETHDEV_PROFILE_WITH_VTUNE
+ return vtune_profile_rx_init(port_id, dev->data->nb_rx_queues);
#endif
return 0;
}
diff --git a/lib/librte_ethdev/ethdev_profile.h b/lib/librte_ethdev/ethdev_profile.h
index e5ea3682..65031e6f 100644
--- a/lib/librte_ethdev/ethdev_profile.h
+++ b/lib/librte_ethdev/ethdev_profile.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2010-2017 Intel Corporation
+ * Copyright(c) 2010-2018 Intel Corporation
*/
#ifndef _RTE_ETHDEV_PROFILE_H_
@@ -8,7 +8,7 @@
#include "rte_ethdev.h"
/**
- * Initialization of profiling RX queues for the Ethernet device.
+ * Initialization of the Ethernet device profiling.
* Implementation of this function depends on chosen profiling method,
* defined in configs.
*
@@ -22,6 +22,6 @@
* - On failure, a negative value.
*/
int
-__rte_eth_profile_rx_init(uint16_t port_id, struct rte_eth_dev *dev);
+__rte_eth_dev_profile_init(uint16_t port_id, struct rte_eth_dev *dev);
#endif
diff --git a/lib/librte_ethdev/meson.build b/lib/librte_ethdev/meson.build
index 596cd0f3..a4d85026 100644
--- a/lib/librte_ethdev/meson.build
+++ b/lib/librte_ethdev/meson.build
@@ -2,9 +2,11 @@
# Copyright(c) 2017 Intel Corporation
name = 'ethdev'
-version = 10
+version = 11
allow_experimental_apis = true
-sources = files('ethdev_profile.c',
+sources = files('ethdev_private.c',
+ 'ethdev_profile.c',
+ 'rte_class_eth.c',
'rte_ethdev.c',
'rte_flow.c',
'rte_mtr.c',
@@ -24,4 +26,4 @@ headers = files('rte_ethdev.h',
'rte_tm.h',
'rte_tm_driver.h')
-deps += ['net', 'kvargs']
+deps += ['net', 'kvargs', 'cmdline']
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
new file mode 100644
index 00000000..cb99c92e
--- /dev/null
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -0,0 +1,173 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <cmdline_parse_etheraddr.h>
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "rte_ethdev_driver.h"
+#include "ethdev_private.h"
+
+enum eth_params {
+ RTE_ETH_PARAM_MAC,
+ RTE_ETH_PARAM_REPRESENTOR,
+ RTE_ETH_PARAM_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+ [RTE_ETH_PARAM_MAC] = "mac",
+ [RTE_ETH_PARAM_REPRESENTOR] = "representor",
+ [RTE_ETH_PARAM_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+ struct rte_device *device;
+ struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+ (&(const struct eth_dev_match_arg) { \
+ .device = (d), \
+ .kvlist = (k), \
+ })
+
+static int
+eth_mac_cmp(const char *key __rte_unused,
+ const char *value, void *opaque)
+{
+ int ret;
+ struct ether_addr mac;
+ const struct rte_eth_dev_data *data = opaque;
+ struct rte_eth_dev_info dev_info;
+ uint32_t index;
+
+ /* Parse devargs MAC address. */
+ /*
+ * cannot use ether_aton_r(value, &mac)
+ * because of include conflict with rte_ether.h
+ */
+ ret = cmdline_parse_etheraddr(NULL, value, &mac, sizeof(mac));
+ if (ret < 0)
+ return -1; /* invalid devargs value */
+
+ /* Return 0 if devargs MAC is matching one of the device MACs. */
+ rte_eth_dev_info_get(data->port_id, &dev_info);
+ for (index = 0; index < dev_info.max_mac_addrs; index++)
+ if (is_same_ether_addr(&mac, &data->mac_addrs[index]))
+ return 0;
+ return -1; /* no match */
+}
+
+static int
+eth_representor_cmp(const char *key __rte_unused,
+ const char *value, void *opaque)
+{
+ int ret;
+ char *values;
+ const struct rte_eth_dev_data *data = opaque;
+ struct rte_eth_devargs representors;
+ uint16_t index;
+
+ if ((data->dev_flags & RTE_ETH_DEV_REPRESENTOR) == 0)
+ return -1; /* not a representor port */
+
+ /* Parse devargs representor values. */
+ values = strdup(value);
+ if (values == NULL)
+ return -1;
+ memset(&representors, 0, sizeof(representors));
+ ret = rte_eth_devargs_parse_list(values,
+ rte_eth_devargs_parse_representor_ports,
+ &representors);
+ free(values);
+ if (ret != 0)
+ return -1; /* invalid devargs value */
+
+ /* Return 0 if representor id is matching one of the values. */
+ for (index = 0; index < representors.nb_representor_ports; index++)
+ if (data->representor_id ==
+ representors.representor_ports[index])
+ return 0;
+ return -1; /* no match */
+}
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+ const void *_arg)
+{
+ int ret;
+ const struct eth_dev_match_arg *arg = _arg;
+ const struct rte_kvargs *kvlist = arg->kvlist;
+ unsigned int pair;
+
+ if (edev->state == RTE_ETH_DEV_UNUSED)
+ return -1;
+ if (arg->device != NULL && arg->device != edev->device)
+ return -1;
+
+ ret = rte_kvargs_process(kvlist,
+ eth_params_keys[RTE_ETH_PARAM_MAC],
+ eth_mac_cmp, edev->data);
+ if (ret != 0)
+ return -1;
+
+ ret = rte_kvargs_process(kvlist,
+ eth_params_keys[RTE_ETH_PARAM_REPRESENTOR],
+ eth_representor_cmp, edev->data);
+ if (ret != 0)
+ return -1;
+ /* search for representor key */
+ for (pair = 0; pair < kvlist->count; pair++) {
+ ret = strcmp(kvlist->pairs[pair].key,
+ eth_params_keys[RTE_ETH_PARAM_REPRESENTOR]);
+ if (ret == 0)
+ break; /* there is a representor key */
+ }
+ /* if no representor key, default is to not match representor ports */
+ if (ret != 0)
+ if ((edev->data->dev_flags & RTE_ETH_DEV_REPRESENTOR) != 0)
+ return -1; /* do not match any representor */
+
+ return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+ const char *str,
+ const struct rte_dev_iterator *it)
+{
+ struct rte_kvargs *kvargs = NULL;
+ struct rte_eth_dev *edev = NULL;
+ const char * const *valid_keys = NULL;
+
+ if (str != NULL) {
+ if (str[0] == '+') /* no validation of keys */
+ str++;
+ else
+ valid_keys = eth_params_keys;
+ kvargs = rte_kvargs_parse(str, valid_keys);
+ if (kvargs == NULL) {
+ RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+ rte_errno = EINVAL;
+ return NULL;
+ }
+ }
+ edev = eth_find_device(start, eth_dev_match,
+ eth_dev_match_arg(it->device, kvargs));
+ rte_kvargs_free(kvargs);
+ return edev;
+}
+
+static struct rte_class rte_class_eth = {
+ .dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index 4c320250..9d348138 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -36,11 +36,13 @@
#include <rte_spinlock.h>
#include <rte_string_fns.h>
#include <rte_kvargs.h>
+#include <rte_class.h>
#include "rte_ether.h"
#include "rte_ethdev.h"
#include "rte_ethdev_driver.h"
#include "ethdev_profile.h"
+#include "ethdev_private.h"
int rte_eth_dev_logtype;
@@ -122,11 +124,12 @@ static const struct {
RTE_RX_OFFLOAD_BIT2STR(VLAN_FILTER),
RTE_RX_OFFLOAD_BIT2STR(VLAN_EXTEND),
RTE_RX_OFFLOAD_BIT2STR(JUMBO_FRAME),
- RTE_RX_OFFLOAD_BIT2STR(CRC_STRIP),
RTE_RX_OFFLOAD_BIT2STR(SCATTER),
RTE_RX_OFFLOAD_BIT2STR(TIMESTAMP),
RTE_RX_OFFLOAD_BIT2STR(SECURITY),
RTE_RX_OFFLOAD_BIT2STR(KEEP_CRC),
+ RTE_RX_OFFLOAD_BIT2STR(SCTP_CKSUM),
+ RTE_RX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
};
#undef RTE_RX_OFFLOAD_BIT2STR
@@ -156,6 +159,10 @@ static const struct {
RTE_TX_OFFLOAD_BIT2STR(MULTI_SEGS),
RTE_TX_OFFLOAD_BIT2STR(MBUF_FAST_FREE),
RTE_TX_OFFLOAD_BIT2STR(SECURITY),
+ RTE_TX_OFFLOAD_BIT2STR(UDP_TNL_TSO),
+ RTE_TX_OFFLOAD_BIT2STR(IP_TNL_TSO),
+ RTE_TX_OFFLOAD_BIT2STR(OUTER_UDP_CKSUM),
+ RTE_TX_OFFLOAD_BIT2STR(MATCH_METADATA),
};
#undef RTE_TX_OFFLOAD_BIT2STR
@@ -180,6 +187,146 @@ enum {
STAT_QMAP_RX
};
+int __rte_experimental
+rte_eth_iterator_init(struct rte_dev_iterator *iter, const char *devargs_str)
+{
+ int ret;
+ struct rte_devargs devargs = {.args = NULL};
+ const char *bus_param_key;
+ char *bus_str = NULL;
+ char *cls_str = NULL;
+ int str_size;
+
+ memset(iter, 0, sizeof(*iter));
+
+ /*
+ * The devargs string may use various syntaxes:
+ * - 0000:08:00.0,representor=[1-3]
+ * - pci:0000:06:00.0,representor=[0,5]
+ * - class=eth,mac=00:11:22:33:44:55
+ * A new syntax is in development (not yet supported):
+ * - bus=X,paramX=x/class=Y,paramY=y/driver=Z,paramZ=z
+ */
+
+ /*
+ * Handle pure class filter (i.e. without any bus-level argument),
+ * from future new syntax.
+ * rte_devargs_parse() is not yet supporting the new syntax,
+ * that's why this simple case is temporarily parsed here.
+ */
+#define iter_anybus_str "class=eth,"
+ if (strncmp(devargs_str, iter_anybus_str,
+ strlen(iter_anybus_str)) == 0) {
+ iter->cls_str = devargs_str + strlen(iter_anybus_str);
+ goto end;
+ }
+
+ /* Split bus, device and parameters. */
+ ret = rte_devargs_parse(&devargs, devargs_str);
+ if (ret != 0)
+ goto error;
+
+ /*
+ * Assume parameters of old syntax can match only at ethdev level.
+ * Extra parameters will be ignored, thanks to "+" prefix.
+ */
+ str_size = strlen(devargs.args) + 2;
+ cls_str = malloc(str_size);
+ if (cls_str == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ ret = snprintf(cls_str, str_size, "+%s", devargs.args);
+ if (ret != str_size - 1) {
+ ret = -EINVAL;
+ goto error;
+ }
+ iter->cls_str = cls_str;
+ free(devargs.args); /* allocated by rte_devargs_parse() */
+ devargs.args = NULL;
+
+ iter->bus = devargs.bus;
+ if (iter->bus->dev_iterate == NULL) {
+ ret = -ENOTSUP;
+ goto error;
+ }
+
+ /* Convert bus args to new syntax for use with new API dev_iterate. */
+ if (strcmp(iter->bus->name, "vdev") == 0) {
+ bus_param_key = "name";
+ } else if (strcmp(iter->bus->name, "pci") == 0) {
+ bus_param_key = "addr";
+ } else {
+ ret = -ENOTSUP;
+ goto error;
+ }
+ str_size = strlen(bus_param_key) + strlen(devargs.name) + 2;
+ bus_str = malloc(str_size);
+ if (bus_str == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ ret = snprintf(bus_str, str_size, "%s=%s",
+ bus_param_key, devargs.name);
+ if (ret != str_size - 1) {
+ ret = -EINVAL;
+ goto error;
+ }
+ iter->bus_str = bus_str;
+
+end:
+ iter->cls = rte_class_find_by_name("eth");
+ return 0;
+
+error:
+ if (ret == -ENOTSUP)
+ RTE_LOG(ERR, EAL, "Bus %s does not support iterating.\n",
+ iter->bus->name);
+ free(devargs.args);
+ free(bus_str);
+ free(cls_str);
+ return ret;
+}
+
+uint16_t __rte_experimental
+rte_eth_iterator_next(struct rte_dev_iterator *iter)
+{
+ if (iter->cls == NULL) /* invalid ethdev iterator */
+ return RTE_MAX_ETHPORTS;
+
+ do { /* loop to try all matching rte_device */
+ /* If not pure ethdev filter and */
+ if (iter->bus != NULL &&
+ /* not in middle of rte_eth_dev iteration, */
+ iter->class_device == NULL) {
+ /* get next rte_device to try. */
+ iter->device = iter->bus->dev_iterate(
+ iter->device, iter->bus_str, iter);
+ if (iter->device == NULL)
+ break; /* no more rte_device candidate */
+ }
+ /* A device is matching bus part, need to check ethdev part. */
+ iter->class_device = iter->cls->dev_iterate(
+ iter->class_device, iter->cls_str, iter);
+ if (iter->class_device != NULL)
+ return eth_dev_to_id(iter->class_device); /* match */
+ } while (iter->bus != NULL); /* need to try next rte_device */
+
+ /* No more ethdev port to iterate. */
+ rte_eth_iterator_cleanup(iter);
+ return RTE_MAX_ETHPORTS;
+}
+
+void __rte_experimental
+rte_eth_iterator_cleanup(struct rte_dev_iterator *iter)
+{
+ if (iter->bus_str == NULL)
+ return; /* nothing to free in pure class filter */
+ free(RTE_CAST_FIELD(iter, bus_str, char *)); /* workaround const */
+ free(RTE_CAST_FIELD(iter, cls_str, char *)); /* workaround const */
+ memset(iter, 0, sizeof(*iter));
+}
+
uint16_t
rte_eth_find_next(uint16_t port_id)
{
@@ -366,13 +513,22 @@ rte_eth_dev_release_port(struct rte_eth_dev *eth_dev)
rte_eth_dev_shared_data_prepare();
- _rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_DESTROY, NULL);
+ if (eth_dev->state != RTE_ETH_DEV_UNUSED)
+ _rte_eth_dev_callback_process(eth_dev,
+ RTE_ETH_EVENT_DESTROY, NULL);
rte_spinlock_lock(&rte_eth_dev_shared_data->ownership_lock);
eth_dev->state = RTE_ETH_DEV_UNUSED;
- memset(eth_dev->data, 0, sizeof(struct rte_eth_dev_data));
+ if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+ rte_free(eth_dev->data->rx_queues);
+ rte_free(eth_dev->data->tx_queues);
+ rte_free(eth_dev->data->mac_addrs);
+ rte_free(eth_dev->data->hash_mac_addrs);
+ rte_free(eth_dev->data->dev_private);
+ memset(eth_dev->data, 0, sizeof(struct rte_eth_dev_data));
+ }
rte_spinlock_unlock(&rte_eth_dev_shared_data->ownership_lock);
@@ -393,11 +549,8 @@ static int
rte_eth_is_valid_owner_id(uint64_t owner_id)
{
if (owner_id == RTE_ETH_DEV_NO_OWNER ||
- rte_eth_dev_shared_data->next_owner_id <= owner_id) {
- RTE_ETHDEV_LOG(ERR, "Invalid owner_id=%016"PRIx64"\n",
- owner_id);
+ rte_eth_dev_shared_data->next_owner_id <= owner_id)
return 0;
- }
return 1;
}
@@ -444,8 +597,12 @@ _rte_eth_dev_owner_set(const uint16_t port_id, const uint64_t old_owner_id,
}
if (!rte_eth_is_valid_owner_id(new_owner->id) &&
- !rte_eth_is_valid_owner_id(old_owner_id))
+ !rte_eth_is_valid_owner_id(old_owner_id)) {
+ RTE_ETHDEV_LOG(ERR,
+ "Invalid owner old_id=%016"PRIx64" new_id=%016"PRIx64"\n",
+ old_owner_id, new_owner->id);
return -EINVAL;
+ }
port_owner = &rte_eth_devices[port_id].data->owner;
if (port_owner->id != old_owner_id) {
@@ -516,9 +673,13 @@ rte_eth_dev_owner_delete(const uint64_t owner_id)
if (rte_eth_devices[port_id].data->owner.id == owner_id)
memset(&rte_eth_devices[port_id].data->owner, 0,
sizeof(struct rte_eth_dev_owner));
- RTE_ETHDEV_LOG(ERR,
+ RTE_ETHDEV_LOG(NOTICE,
"All port owners owned by %016"PRIx64" identifier have removed\n",
owner_id);
+ } else {
+ RTE_ETHDEV_LOG(ERR,
+ "Invalid owner id=%016"PRIx64"\n",
+ owner_id);
}
rte_spinlock_unlock(&rte_eth_dev_shared_data->ownership_lock);
@@ -642,87 +803,6 @@ eth_err(uint16_t port_id, int ret)
return ret;
}
-/* attach the new device, then store port_id of the device */
-int
-rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
-{
- int current = rte_eth_dev_count_total();
- struct rte_devargs da;
- int ret = -1;
-
- memset(&da, 0, sizeof(da));
-
- if ((devargs == NULL) || (port_id == NULL)) {
- ret = -EINVAL;
- goto err;
- }
-
- /* parse devargs */
- if (rte_devargs_parse(&da, devargs))
- goto err;
-
- ret = rte_eal_hotplug_add(da.bus->name, da.name, da.args);
- if (ret < 0)
- goto err;
-
- /* no point looking at the port count if no port exists */
- if (!rte_eth_dev_count_total()) {
- RTE_ETHDEV_LOG(ERR, "No port found for device (%s)\n", da.name);
- ret = -1;
- goto err;
- }
-
- /* if nothing happened, there is a bug here, since some driver told us
- * it did attach a device, but did not create a port.
- * FIXME: race condition in case of plug-out of another device
- */
- if (current == rte_eth_dev_count_total()) {
- ret = -1;
- goto err;
- }
-
- *port_id = eth_dev_last_created_port;
- ret = 0;
-
-err:
- free(da.args);
- return ret;
-}
-
-/* detach the device, then store the name of the device */
-int
-rte_eth_dev_detach(uint16_t port_id, char *name __rte_unused)
-{
- struct rte_device *dev;
- struct rte_bus *bus;
- uint32_t dev_flags;
- int ret = -1;
-
- RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
-
- dev_flags = rte_eth_devices[port_id].data->dev_flags;
- if (dev_flags & RTE_ETH_DEV_BONDED_SLAVE) {
- RTE_ETHDEV_LOG(ERR,
- "Port %"PRIu16" is bonded, cannot detach\n", port_id);
- return -ENOTSUP;
- }
-
- dev = rte_eth_devices[port_id].device;
- if (dev == NULL)
- return -EINVAL;
-
- bus = rte_bus_find_by_device(dev);
- if (bus == NULL)
- return -ENOENT;
-
- ret = rte_eal_hotplug_remove(bus->name, dev->name);
- if (ret < 0)
- return ret;
-
- rte_eth_dev_release_port(&rte_eth_devices[port_id]);
- return 0;
-}
-
static int
rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
{
@@ -974,7 +1054,7 @@ rte_eth_speed_bitflag(uint32_t speed, int duplex)
}
}
-const char * __rte_experimental
+const char *
rte_eth_dev_rx_offload_name(uint64_t offload)
{
const char *name = "UNKNOWN";
@@ -990,7 +1070,7 @@ rte_eth_dev_rx_offload_name(uint64_t offload)
return name;
}
-const char * __rte_experimental
+const char *
rte_eth_dev_tx_offload_name(uint64_t offload)
{
const char *name = "UNKNOWN";
@@ -1142,14 +1222,6 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
return -EINVAL;
}
- if ((local_conf.rxmode.offloads & DEV_RX_OFFLOAD_CRC_STRIP) &&
- (local_conf.rxmode.offloads & DEV_RX_OFFLOAD_KEEP_CRC)) {
- RTE_ETHDEV_LOG(ERR,
- "Port id=%u not allowed to set both CRC STRIP and KEEP CRC offload flags\n",
- port_id);
- return -EINVAL;
- }
-
/* Check that device supports requested rss hash functions. */
if ((dev_info.flow_type_rss_offloads |
dev_conf->rx_adv_conf.rss_conf.rss_hf) !=
@@ -1191,9 +1263,9 @@ rte_eth_dev_configure(uint16_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
}
/* Initialize Rx profiling if enabled at compilation time. */
- diag = __rte_eth_profile_rx_init(port_id, dev);
+ diag = __rte_eth_dev_profile_init(port_id, dev);
if (diag != 0) {
- RTE_ETHDEV_LOG(ERR, "Port%u __rte_eth_profile_rx_init = %d\n",
+ RTE_ETHDEV_LOG(ERR, "Port%u __rte_eth_dev_profile_init = %d\n",
port_id, diag);
rte_eth_dev_rx_queue_config(dev, 0);
rte_eth_dev_tx_queue_config(dev, 0);
@@ -1219,19 +1291,14 @@ _rte_eth_dev_reset(struct rte_eth_dev *dev)
}
static void
-rte_eth_dev_config_restore(uint16_t port_id)
+rte_eth_dev_mac_restore(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info)
{
- struct rte_eth_dev *dev;
- struct rte_eth_dev_info dev_info;
struct ether_addr *addr;
uint16_t i;
uint32_t pool = 0;
uint64_t pool_mask;
- dev = &rte_eth_devices[port_id];
-
- rte_eth_dev_info_get(port_id, &dev_info);
-
/* replay MAC address configuration including default MAC */
addr = &dev->data->mac_addrs[0];
if (*dev->dev_ops->mac_addr_set != NULL)
@@ -1240,7 +1307,7 @@ rte_eth_dev_config_restore(uint16_t port_id)
(*dev->dev_ops->mac_addr_add)(dev, addr, 0, pool);
if (*dev->dev_ops->mac_addr_add != NULL) {
- for (i = 1; i < dev_info.max_mac_addrs; i++) {
+ for (i = 1; i < dev_info->max_mac_addrs; i++) {
addr = &dev->data->mac_addrs[i];
/* skip zero address */
@@ -1259,6 +1326,14 @@ rte_eth_dev_config_restore(uint16_t port_id)
} while (pool_mask);
}
}
+}
+
+static void
+rte_eth_dev_config_restore(struct rte_eth_dev *dev,
+ struct rte_eth_dev_info *dev_info, uint16_t port_id)
+{
+ if (!(*dev_info->dev_flags & RTE_ETH_DEV_NOLIVE_MAC_ADDR))
+ rte_eth_dev_mac_restore(dev, dev_info);
/* replay promiscuous configuration */
if (rte_eth_promiscuous_get(port_id) == 1)
@@ -1277,6 +1352,7 @@ int
rte_eth_dev_start(uint16_t port_id)
{
struct rte_eth_dev *dev;
+ struct rte_eth_dev_info dev_info;
int diag;
RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
@@ -1292,13 +1368,19 @@ rte_eth_dev_start(uint16_t port_id)
return 0;
}
+ rte_eth_dev_info_get(port_id, &dev_info);
+
+ /* Lets restore MAC now if device does not support live change */
+ if (*dev_info.dev_flags & RTE_ETH_DEV_NOLIVE_MAC_ADDR)
+ rte_eth_dev_mac_restore(dev, &dev_info);
+
diag = (*dev->dev_ops->dev_start)(dev);
if (diag == 0)
dev->data->dev_started = 1;
else
return eth_err(port_id, diag);
- rte_eth_dev_config_restore(port_id);
+ rte_eth_dev_config_restore(dev, &dev_info, port_id);
if (dev->data->dev_conf.intr_conf.lsc == 0) {
RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->link_update, -ENOTSUP);
@@ -1366,6 +1448,16 @@ rte_eth_dev_close(uint16_t port_id)
dev->data->dev_started = 0;
(*dev->dev_ops->dev_close)(dev);
+ /* check behaviour flag - temporary for PMD migration */
+ if ((dev->data->dev_flags & RTE_ETH_DEV_CLOSE_REMOVE) != 0) {
+ /* new behaviour: send event + reset state + free all data */
+ rte_eth_dev_release_port(dev);
+ return;
+ }
+ RTE_ETHDEV_LOG(DEBUG, "Port closing is using an old behaviour.\n"
+ "The driver %s should migrate to the new behaviour.\n",
+ dev->device->driver->name);
+ /* old behaviour: only free queue arrays */
dev->data->nb_rx_queues = 0;
rte_free(dev->data->rx_queues);
dev->data->rx_queues = NULL;
@@ -3425,6 +3517,43 @@ rte_eth_dev_rx_intr_ctl(uint16_t port_id, int epfd, int op, void *data)
return 0;
}
+int __rte_experimental
+rte_eth_dev_rx_intr_ctl_q_get_fd(uint16_t port_id, uint16_t queue_id)
+{
+ struct rte_intr_handle *intr_handle;
+ struct rte_eth_dev *dev;
+ unsigned int efd_idx;
+ uint32_t vec;
+ int fd;
+
+ RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -1);
+
+ dev = &rte_eth_devices[port_id];
+
+ if (queue_id >= dev->data->nb_rx_queues) {
+ RTE_ETHDEV_LOG(ERR, "Invalid RX queue_id=%u\n", queue_id);
+ return -1;
+ }
+
+ if (!dev->intr_handle) {
+ RTE_ETHDEV_LOG(ERR, "RX Intr handle unset\n");
+ return -1;
+ }
+
+ intr_handle = dev->intr_handle;
+ if (!intr_handle->intr_vec) {
+ RTE_ETHDEV_LOG(ERR, "RX Intr vector unset\n");
+ return -1;
+ }
+
+ vec = intr_handle->intr_vec[queue_id];
+ efd_idx = (vec >= RTE_INTR_VEC_RXTX_OFFSET) ?
+ (vec - RTE_INTR_VEC_RXTX_OFFSET) : vec;
+ fd = intr_handle->efds[efd_idx];
+
+ return fd;
+}
+
const struct rte_memzone *
rte_eth_dma_zone_reserve(const struct rte_eth_dev *dev, const char *ring_name,
uint16_t queue_id, size_t size, unsigned align,
@@ -3433,9 +3562,8 @@ rte_eth_dma_zone_reserve(const struct rte_eth_dev *dev, const char *ring_name,
char z_name[RTE_MEMZONE_NAMESIZE];
const struct rte_memzone *mz;
- snprintf(z_name, sizeof(z_name), "%s_%s_%d_%d",
- dev->device->driver->name, ring_name,
- dev->data->port_id, queue_id);
+ snprintf(z_name, sizeof(z_name), "eth_p%d_q%d_%s",
+ dev->data->port_id, queue_id, ring_name);
mz = rte_memzone_lookup(z_name);
if (mz)
@@ -3459,10 +3587,8 @@ rte_eth_dev_create(struct rte_device *device, const char *name,
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
ethdev = rte_eth_dev_allocate(name);
- if (!ethdev) {
- retval = -ENODEV;
- goto probe_failed;
- }
+ if (!ethdev)
+ return -ENODEV;
if (priv_data_size) {
ethdev->data->dev_private = rte_zmalloc_socket(
@@ -3480,8 +3606,7 @@ rte_eth_dev_create(struct rte_device *device, const char *name,
if (!ethdev) {
RTE_LOG(ERR, EAL, "secondary process attach failed, "
"ethdev doesn't exist");
- retval = -ENODEV;
- goto probe_failed;
+ return -ENODEV;
}
}
@@ -3505,13 +3630,9 @@ rte_eth_dev_create(struct rte_device *device, const char *name,
rte_eth_dev_probing_finish(ethdev);
return retval;
-probe_failed:
- /* free ports private data if primary process */
- if (rte_eal_process_type() == RTE_PROC_PRIMARY)
- rte_free(ethdev->data->dev_private);
+probe_failed:
rte_eth_dev_release_port(ethdev);
-
return retval;
}
@@ -3532,11 +3653,6 @@ rte_eth_dev_destroy(struct rte_eth_dev *ethdev,
return ret;
}
- if (rte_eal_process_type() == RTE_PROC_PRIMARY)
- rte_free(ethdev->data->dev_private);
-
- ethdev->data->dev_private = NULL;
-
return rte_eth_dev_release_port(ethdev);
}
@@ -4195,7 +4311,7 @@ enum rte_eth_switch_domain_state {
* RTE_MAX_ETHPORTS elements as there cannot be more active switch domains than
* ethdev ports in a single process.
*/
-struct rte_eth_dev_switch {
+static struct rte_eth_dev_switch {
enum rte_eth_switch_domain_state state;
} rte_eth_switch_domains[RTE_MAX_ETHPORTS];
@@ -4236,8 +4352,6 @@ rte_eth_switch_domain_free(uint16_t domain_id)
return 0;
}
-typedef int (*rte_eth_devargs_callback_t)(char *str, void *data);
-
static int
rte_eth_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
{
@@ -4302,89 +4416,6 @@ rte_eth_devargs_tokenise(struct rte_kvargs *arglist, const char *str_in)
}
}
-static int
-rte_eth_devargs_parse_list(char *str, rte_eth_devargs_callback_t callback,
- void *data)
-{
- char *str_start;
- int state;
- int result;
-
- if (*str != '[')
- /* Single element, not a list */
- return callback(str, data);
-
- /* Sanity check, then strip the brackets */
- str_start = &str[strlen(str) - 1];
- if (*str_start != ']') {
- RTE_LOG(ERR, EAL, "(%s): List does not end with ']'", str);
- return -EINVAL;
- }
- str++;
- *str_start = '\0';
-
- /* Process list elements */
- state = 0;
- while (1) {
- if (state == 0) {
- if (*str == '\0')
- break;
- if (*str != ',') {
- str_start = str;
- state = 1;
- }
- } else if (state == 1) {
- if (*str == ',' || *str == '\0') {
- if (str > str_start) {
- /* Non-empty string fragment */
- *str = '\0';
- result = callback(str_start, data);
- if (result < 0)
- return result;
- }
- state = 0;
- }
- }
- str++;
- }
- return 0;
-}
-
-static int
-rte_eth_devargs_process_range(char *str, uint16_t *list, uint16_t *len_list,
- const uint16_t max_list)
-{
- uint16_t lo, hi, val;
- int result;
-
- result = sscanf(str, "%hu-%hu", &lo, &hi);
- if (result == 1) {
- if (*len_list >= max_list)
- return -ENOMEM;
- list[(*len_list)++] = lo;
- } else if (result == 2) {
- if (lo >= hi || lo > RTE_MAX_ETHPORTS || hi > RTE_MAX_ETHPORTS)
- return -EINVAL;
- for (val = lo; val <= hi; val++) {
- if (*len_list >= max_list)
- return -ENOMEM;
- list[(*len_list)++] = val;
- }
- } else
- return -EINVAL;
- return 0;
-}
-
-
-static int
-rte_eth_devargs_parse_representor_ports(char *str, void *data)
-{
- struct rte_eth_devargs *eth_da = data;
-
- return rte_eth_devargs_process_range(str, eth_da->representor_ports,
- &eth_da->nb_representor_ports, RTE_MAX_ETHPORTS);
-}
-
int __rte_experimental
rte_eth_devargs_parse(const char *dargs, struct rte_eth_devargs *eth_da)
{
diff --git a/lib/librte_ethdev/rte_ethdev.h b/lib/librte_ethdev/rte_ethdev.h
index 7070e9ab..769a6943 100644
--- a/lib/librte_ethdev/rte_ethdev.h
+++ b/lib/librte_ethdev/rte_ethdev.h
@@ -167,6 +167,85 @@ extern int rte_eth_dev_logtype;
struct rte_mbuf;
/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Initializes a device iterator.
+ *
+ * This iterator allows accessing a list of devices matching some devargs.
+ *
+ * @param iter
+ * Device iterator handle initialized by the function.
+ * The fields bus_str and cls_str might be dynamically allocated,
+ * and could be freed by calling rte_eth_iterator_cleanup().
+ *
+ * @param devargs
+ * Device description string.
+ *
+ * @return
+ * 0 on successful initialization, negative otherwise.
+ */
+__rte_experimental
+int rte_eth_iterator_init(struct rte_dev_iterator *iter, const char *devargs);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Iterates on devices with devargs filter.
+ * The ownership is not checked.
+ *
+ * The next port id is returned, and the iterator is updated.
+ *
+ * @param iter
+ * Device iterator handle initialized by rte_eth_iterator_init().
+ * Some fields bus_str and cls_str might be freed when no more port is found,
+ * by calling rte_eth_iterator_cleanup().
+ *
+ * @return
+ * A port id if found, RTE_MAX_ETHPORTS otherwise.
+ */
+__rte_experimental
+uint16_t rte_eth_iterator_next(struct rte_dev_iterator *iter);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Free some allocated fields of the iterator.
+ *
+ * This function is automatically called by rte_eth_iterator_next()
+ * on the last iteration (i.e. when no more matching port is found).
+ *
+ * It is safe to call this function twice; it will do nothing more.
+ *
+ * @param iter
+ * Device iterator handle initialized by rte_eth_iterator_init().
+ * The fields bus_str and cls_str are freed if needed.
+ */
+__rte_experimental
+void rte_eth_iterator_cleanup(struct rte_dev_iterator *iter);
+
+/**
+ * Macro to iterate over all ethdev ports matching some devargs.
+ *
+ * If a break is done before the end of the loop,
+ * the function rte_eth_iterator_cleanup() must be called.
+ *
+ * @param id
+ * Iterated port id of type uint16_t.
+ * @param devargs
+ * Device parameters input as string of type char*.
+ * @param iter
+ * Iterator handle of type struct rte_dev_iterator, used internally.
+ */
+#define RTE_ETH_FOREACH_MATCHING_DEV(id, devargs, iter) \
+ for (rte_eth_iterator_init(iter, devargs), \
+ id = rte_eth_iterator_next(iter); \
+ id != RTE_MAX_ETHPORTS; \
+ id = rte_eth_iterator_next(iter))
+
+/**
* A structure used to retrieve statistics for an Ethernet port.
* Not all statistics fields in struct rte_eth_stats are supported
* by any type of network interface card (NIC). If any statistics
@@ -870,12 +949,6 @@ struct rte_eth_conf {
};
/**
- * A structure used to retrieve the contextual information of
- * an Ethernet device, such as the controlling driver of the device,
- * its PCI context, etc...
- */
-
-/**
* RX offload capabilities of a device.
*/
#define DEV_RX_OFFLOAD_VLAN_STRIP 0x00000001
@@ -890,16 +963,13 @@ struct rte_eth_conf {
#define DEV_RX_OFFLOAD_VLAN_FILTER 0x00000200
#define DEV_RX_OFFLOAD_VLAN_EXTEND 0x00000400
#define DEV_RX_OFFLOAD_JUMBO_FRAME 0x00000800
-#define DEV_RX_OFFLOAD_CRC_STRIP 0x00001000
#define DEV_RX_OFFLOAD_SCATTER 0x00002000
#define DEV_RX_OFFLOAD_TIMESTAMP 0x00004000
#define DEV_RX_OFFLOAD_SECURITY 0x00008000
-
-/**
- * Invalid to set both DEV_RX_OFFLOAD_CRC_STRIP and DEV_RX_OFFLOAD_KEEP_CRC
- * No DEV_RX_OFFLOAD_CRC_STRIP flag means keep CRC
- */
#define DEV_RX_OFFLOAD_KEEP_CRC 0x00010000
+#define DEV_RX_OFFLOAD_SCTP_CKSUM 0x00020000
+#define DEV_RX_OFFLOAD_OUTER_UDP_CKSUM 0x00040000
+
#define DEV_RX_OFFLOAD_CHECKSUM (DEV_RX_OFFLOAD_IPV4_CKSUM | \
DEV_RX_OFFLOAD_UDP_CKSUM | \
DEV_RX_OFFLOAD_TCP_CKSUM)
@@ -953,6 +1023,13 @@ struct rte_eth_conf {
* for tunnel TSO.
*/
#define DEV_TX_OFFLOAD_IP_TNL_TSO 0x00080000
+/** Device supports outer UDP checksum */
+#define DEV_TX_OFFLOAD_OUTER_UDP_CKSUM 0x00100000
+/**
+ * Device supports match on metadata Tx offload..
+ * Application must set PKT_TX_METADATA and mbuf metadata field.
+ */
+#define DEV_TX_OFFLOAD_MATCH_METADATA 0x00200000
#define RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP 0x00000001
/**< Device supports Rx queue setup after device started*/
@@ -1010,6 +1087,12 @@ struct rte_eth_switch_info {
/**
* Ethernet device information
*/
+
+/**
+ * A structure used to retrieve the contextual information of
+ * an Ethernet device, such as the controlling driver of the
+ * device, etc...
+ */
struct rte_eth_dev_info {
struct rte_device *device; /** Generic device information */
const char *driver_name; /**< Device Driver name. */
@@ -1260,6 +1343,11 @@ struct rte_eth_dev_owner {
char name[RTE_ETH_MAX_OWNER_NAME_LEN]; /**< The owner name. */
};
+/**
+ * Port is released (i.e. totally freed and data erased) on close.
+ * Temporary flag for PMD migration to new rte_eth_dev_close() behaviour.
+ */
+#define RTE_ETH_DEV_CLOSE_REMOVE 0x0001
/** Device supports link state interrupt */
#define RTE_ETH_DEV_INTR_LSC 0x0002
/** Device is a bonded slave */
@@ -1268,6 +1356,8 @@ struct rte_eth_dev_owner {
#define RTE_ETH_DEV_INTR_RMV 0x0008
/** Device is port representor */
#define RTE_ETH_DEV_REPRESENTOR 0x0010
+/** Device does not support MAC change after started */
+#define RTE_ETH_DEV_NOLIVE_MAC_ADDR 0x0020
/**
* Iterates over valid ethdev ports owned by a specific owner.
@@ -1420,37 +1510,6 @@ uint16_t rte_eth_dev_count_avail(void);
uint16_t __rte_experimental rte_eth_dev_count_total(void);
/**
- * Attach a new Ethernet device specified by arguments.
- *
- * @param devargs
- * A pointer to a strings array describing the new device
- * to be attached. The strings should be a pci address like
- * '0000:01:00.0' or virtual device name like 'net_pcap0'.
- * @param port_id
- * A pointer to a port identifier actually attached.
- * @return
- * 0 on success and port_id is filled, negative on error
- */
-__rte_deprecated
-int rte_eth_dev_attach(const char *devargs, uint16_t *port_id);
-
-/**
- * Detach a Ethernet device specified by port identifier.
- * This function must be called when the device is in the
- * closed state.
- *
- * @param port_id
- * The port identifier of the device to detach.
- * @param devname
- * A pointer to a buffer that will be filled with the device name.
- * This buffer must be at least RTE_DEV_NAME_MAX_LEN long.
- * @return
- * 0 on success and devname is filled, negative on error
- */
-__rte_deprecated
-int rte_eth_dev_detach(uint16_t port_id, char *devname);
-
-/**
* Convert a numerical speed in Mbps to a bitmap flag that can be used in
* the bitmap link_speeds of the struct rte_eth_conf
*
@@ -1464,9 +1523,6 @@ int rte_eth_dev_detach(uint16_t port_id, char *devname);
uint32_t rte_eth_speed_bitflag(uint32_t speed, int duplex);
/**
- * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
- *
* Get DEV_RX_OFFLOAD_* flag name.
*
* @param offload
@@ -1474,12 +1530,9 @@ uint32_t rte_eth_speed_bitflag(uint32_t speed, int duplex);
* @return
* Offload name or 'UNKNOWN' if the flag cannot be recognised.
*/
-const char * __rte_experimental rte_eth_dev_rx_offload_name(uint64_t offload);
+const char *rte_eth_dev_rx_offload_name(uint64_t offload);
/**
- * @warning
- * @b EXPERIMENTAL: this API may change without prior notice
- *
* Get DEV_TX_OFFLOAD_* flag name.
*
* @param offload
@@ -1487,7 +1540,7 @@ const char * __rte_experimental rte_eth_dev_rx_offload_name(uint64_t offload);
* @return
* Offload name or 'UNKNOWN' if the flag cannot be recognised.
*/
-const char * __rte_experimental rte_eth_dev_tx_offload_name(uint64_t offload);
+const char *rte_eth_dev_tx_offload_name(uint64_t offload);
/**
* Configure an Ethernet device.
@@ -1750,6 +1803,10 @@ int rte_eth_dev_tx_queue_stop(uint16_t port_id, uint16_t tx_queue_id);
* The device start step is the last one and consists of setting the configured
* offload features and in starting the transmit and the receive units of the
* device.
+ *
+ * Device RTE_ETH_DEV_NOLIVE_MAC_ADDR flag causes MAC address to be set before
+ * PMD port start callback function is invoked.
+ *
* On success, all basic functions exported by the Ethernet API (link status,
* receive/transmit, and so on) can be invoked.
*
@@ -1797,8 +1854,8 @@ int rte_eth_dev_set_link_down(uint16_t port_id);
/**
* Close a stopped Ethernet device. The device cannot be restarted!
- * The function frees all resources except for needed by the
- * closed state. To free these resources, call rte_eth_dev_detach().
+ * The function frees all port resources if the driver supports
+ * the flag RTE_ETH_DEV_CLOSE_REMOVE.
*
* @param port_id
* The port identifier of the Ethernet device.
@@ -2719,6 +2776,26 @@ int rte_eth_dev_rx_intr_ctl_q(uint16_t port_id, uint16_t queue_id,
int epfd, int op, void *data);
/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Get interrupt fd per Rx queue.
+ *
+ * @param port_id
+ * The port identifier of the Ethernet device.
+ * @param queue_id
+ * The index of the receive queue from which to retrieve input packets.
+ * The value must be in the range [0, nb_rx_queue - 1] previously supplied
+ * to rte_eth_dev_configure().
+ * @return
+ * - (>=0) the interrupt fd associated to the requested Rx queue if
+ * successful.
+ * - (-1) on error.
+ */
+int __rte_experimental
+rte_eth_dev_rx_intr_ctl_q_get_fd(uint16_t port_id, uint16_t queue_id);
+
+/**
* Turn on the LED on the Ethernet device.
* This function turns on the LED on the Ethernet device.
*
diff --git a/lib/librte_ethdev/rte_ethdev_core.h b/lib/librte_ethdev/rte_ethdev_core.h
index 33d12b3a..8f03f83f 100644
--- a/lib/librte_ethdev/rte_ethdev_core.h
+++ b/lib/librte_ethdev/rte_ethdev_core.h
@@ -539,7 +539,13 @@ struct rte_eth_dev {
eth_rx_burst_t rx_pkt_burst; /**< Pointer to PMD receive function. */
eth_tx_burst_t tx_pkt_burst; /**< Pointer to PMD transmit function. */
eth_tx_prep_t tx_pkt_prepare; /**< Pointer to PMD transmit prepare function. */
- struct rte_eth_dev_data *data; /**< Pointer to device data */
+ /**
+ * Next two fields are per-device data but *data is shared between
+ * primary and secondary processes and *process_private is per-process
+ * private. The second one is managed by PMDs if necessary.
+ */
+ struct rte_eth_dev_data *data; /**< Pointer to device data. */
+ void *process_private; /**< Pointer to per-process device data. */
const struct eth_dev_ops *dev_ops; /**< Functions exported by PMD */
struct rte_device *device; /**< Backing device */
struct rte_intr_handle *intr_handle; /**< Device interrupt handle */
@@ -579,24 +585,30 @@ struct rte_eth_dev_data {
struct rte_eth_dev_sriov sriov; /**< SRIOV data */
- void *dev_private; /**< PMD-specific private data */
-
- struct rte_eth_link dev_link;
- /**< Link-level information & status */
+ void *dev_private;
+ /**< PMD-specific private data.
+ * @see rte_eth_dev_release_port()
+ */
+ struct rte_eth_link dev_link; /**< Link-level information & status. */
struct rte_eth_conf dev_conf; /**< Configuration applied to device. */
uint16_t mtu; /**< Maximum Transmission Unit. */
-
uint32_t min_rx_buf_size;
- /**< Common rx buffer size handled by all queues */
+ /**< Common RX buffer size handled by all queues. */
uint64_t rx_mbuf_alloc_failed; /**< RX ring mbuf allocation failures. */
- struct ether_addr* mac_addrs;/**< Device Ethernet Link address. */
+ struct ether_addr *mac_addrs;
+ /**< Device Ethernet link address.
+ * @see rte_eth_dev_release_port()
+ */
uint64_t mac_pool_sel[ETH_NUM_RECEIVE_MAC_ADDR];
- /** bitmap array of associating Ethernet MAC addresses to pools */
- struct ether_addr* hash_mac_addrs;
- /** Device Ethernet MAC addresses of hash filtering. */
+ /**< Bitmap associating MAC addresses to pools. */
+ struct ether_addr *hash_mac_addrs;
+ /**< Device Ethernet MAC addresses of hash filtering.
+ * @see rte_eth_dev_release_port()
+ */
uint16_t port_id; /**< Device [external] port identifier. */
+
__extension__
uint8_t promiscuous : 1, /**< RX promiscuous mode ON(1) / OFF(0). */
scattered_rx : 1, /**< RX of scattered packets is ON(1) / OFF(0) */
@@ -604,15 +616,19 @@ struct rte_eth_dev_data {
dev_started : 1, /**< Device state: STARTED(1) / STOPPED(0). */
lro : 1; /**< RX LRO is ON(1) / OFF(0) */
uint8_t rx_queue_state[RTE_MAX_QUEUES_PER_PORT];
- /** Queues state: STARTED(1) / STOPPED(0) */
+ /**< Queues state: STARTED(1) / STOPPED(0). */
uint8_t tx_queue_state[RTE_MAX_QUEUES_PER_PORT];
- /** Queues state: STARTED(1) / STOPPED(0) */
- uint32_t dev_flags; /**< Capabilities */
- enum rte_kernel_driver kdrv; /**< Kernel driver passthrough */
- int numa_node; /**< NUMA node connection */
+ /**< Queues state: STARTED(1) / STOPPED(0). */
+ uint32_t dev_flags; /**< Capabilities. */
+ enum rte_kernel_driver kdrv; /**< Kernel driver passthrough. */
+ int numa_node; /**< NUMA node connection. */
struct rte_vlan_filter_conf vlan_filter_conf;
- /**< VLAN filter configuration. */
+ /**< VLAN filter configuration. */
struct rte_eth_dev_owner owner; /**< The port owner. */
+ uint16_t representor_id;
+ /**< Switch-specific identifier.
+ * Valid if RTE_ETH_DEV_REPRESENTOR in dev_flags.
+ */
} __rte_cache_aligned;
/**
diff --git a/lib/librte_ethdev/rte_ethdev_driver.h b/lib/librte_ethdev/rte_ethdev_driver.h
index c6d9bc1a..c2ac2632 100644
--- a/lib/librte_ethdev/rte_ethdev_driver.h
+++ b/lib/librte_ethdev/rte_ethdev_driver.h
@@ -58,10 +58,17 @@ struct rte_eth_dev *rte_eth_dev_attach_secondary(const char *name);
/**
* @internal
- * Release the specified ethdev port.
+ * Notify RTE_ETH_EVENT_DESTROY and release the specified ethdev port.
+ *
+ * The following PMD-managed data fields will be freed:
+ * - dev_private
+ * - mac_addrs
+ * - hash_mac_addrs
+ * If one of these fields should not be freed,
+ * it must be reset to NULL by the PMD, typically in dev_close method.
*
* @param eth_dev
- * The *eth_dev* pointer is the address of the *rte_eth_dev* structure.
+ * Device to be detached.
* @return
* - 0 on success, negative on error
*/
@@ -324,32 +331,6 @@ typedef int (*ethdev_uninit_t)(struct rte_eth_dev *ethdev);
int __rte_experimental
rte_eth_dev_destroy(struct rte_eth_dev *ethdev, ethdev_uninit_t ethdev_uninit);
-/**
- * PMD helper function to check if keeping CRC is requested
- *
- * @note
- * When CRC_STRIP offload flag is removed and default behavior switch to
- * strip CRC, as planned, this helper function is not that useful and will be
- * removed. In PMDs this function will be replaced with check:
- * if (offloads & DEV_RX_OFFLOAD_KEEP_CRC)
- *
- * @param rx_offloads
- * offload bits to be applied
- *
- * @return
- * Return positive if keeping CRC is requested,
- * zero if stripping CRC is requested
- */
-static inline int
-rte_eth_dev_must_keep_crc(uint64_t rx_offloads)
-{
- if (rx_offloads & DEV_RX_OFFLOAD_CRC_STRIP)
- return 0;
-
- /* no KEEP_CRC or CRC_STRIP offload flags means keep CRC */
- return 1;
-}
-
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_ethdev/rte_ethdev_pci.h b/lib/librte_ethdev/rte_ethdev_pci.h
index f652596f..23257e98 100644
--- a/lib/librte_ethdev/rte_ethdev_pci.h
+++ b/lib/librte_ethdev/rte_ethdev_pci.h
@@ -135,17 +135,6 @@ rte_eth_dev_pci_allocate(struct rte_pci_device *dev, size_t private_data_size)
static inline void
rte_eth_dev_pci_release(struct rte_eth_dev *eth_dev)
{
- if (rte_eal_process_type() == RTE_PROC_PRIMARY)
- rte_free(eth_dev->data->dev_private);
-
- eth_dev->data->dev_private = NULL;
-
- /*
- * Secondary process will check the name to attach.
- * Clear this field to avoid attaching a released ports.
- */
- eth_dev->data->name[0] = '\0';
-
eth_dev->device = NULL;
eth_dev->intr_handle = NULL;
diff --git a/lib/librte_ethdev/rte_ethdev_version.map b/lib/librte_ethdev/rte_ethdev_version.map
index 38f117f0..3560c288 100644
--- a/lib/librte_ethdev/rte_ethdev_version.map
+++ b/lib/librte_ethdev/rte_ethdev_version.map
@@ -8,14 +8,12 @@ DPDK_2.2 {
rte_eth_allmulticast_get;
rte_eth_dev_allocate;
rte_eth_dev_allocated;
- rte_eth_dev_attach;
rte_eth_dev_callback_register;
rte_eth_dev_callback_unregister;
rte_eth_dev_close;
rte_eth_dev_configure;
rte_eth_dev_count;
rte_eth_dev_default_mac_addr_set;
- rte_eth_dev_detach;
rte_eth_dev_filter_supported;
rte_eth_dev_flow_ctrl_get;
rte_eth_dev_flow_ctrl_set;
@@ -220,6 +218,14 @@ DPDK_18.08 {
} DPDK_18.05;
+DPDK_18.11 {
+ global:
+
+ rte_eth_dev_rx_offload_name;
+ rte_eth_dev_tx_offload_name;
+
+} DPDK_18.08;
+
EXPERIMENTAL {
global:
@@ -235,10 +241,13 @@ EXPERIMENTAL {
rte_eth_dev_owner_new;
rte_eth_dev_owner_set;
rte_eth_dev_owner_unset;
- rte_eth_dev_rx_offload_name;
- rte_eth_dev_tx_offload_name;
+ rte_eth_dev_rx_intr_ctl_q_get_fd;
+ rte_eth_iterator_cleanup;
+ rte_eth_iterator_init;
+ rte_eth_iterator_next;
rte_eth_switch_domain_alloc;
rte_eth_switch_domain_free;
+ rte_flow_conv;
rte_flow_expand_rss;
rte_mtr_capabilities_get;
rte_mtr_create;
diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c
index cff4b520..3277be1e 100644
--- a/lib/librte_ethdev/rte_flow.c
+++ b/lib/librte_ethdev/rte_flow.c
@@ -11,6 +11,7 @@
#include <rte_common.h>
#include <rte_errno.h>
#include <rte_branch_prediction.h>
+#include <rte_string_fns.h>
#include "rte_ethdev.h"
#include "rte_flow_driver.h"
#include "rte_flow.h"
@@ -50,10 +51,15 @@ static const struct rte_flow_desc_data rte_flow_desc_item[] = {
MK_FLOW_ITEM(TCP, sizeof(struct rte_flow_item_tcp)),
MK_FLOW_ITEM(SCTP, sizeof(struct rte_flow_item_sctp)),
MK_FLOW_ITEM(VXLAN, sizeof(struct rte_flow_item_vxlan)),
- MK_FLOW_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
- MK_FLOW_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
MK_FLOW_ITEM(E_TAG, sizeof(struct rte_flow_item_e_tag)),
MK_FLOW_ITEM(NVGRE, sizeof(struct rte_flow_item_nvgre)),
+ MK_FLOW_ITEM(MPLS, sizeof(struct rte_flow_item_mpls)),
+ MK_FLOW_ITEM(GRE, sizeof(struct rte_flow_item_gre)),
+ MK_FLOW_ITEM(FUZZY, sizeof(struct rte_flow_item_fuzzy)),
+ MK_FLOW_ITEM(GTP, sizeof(struct rte_flow_item_gtp)),
+ MK_FLOW_ITEM(GTPC, sizeof(struct rte_flow_item_gtp)),
+ MK_FLOW_ITEM(GTPU, sizeof(struct rte_flow_item_gtp)),
+ MK_FLOW_ITEM(ESP, sizeof(struct rte_flow_item_esp)),
MK_FLOW_ITEM(GENEVE, sizeof(struct rte_flow_item_geneve)),
MK_FLOW_ITEM(VXLAN_GPE, sizeof(struct rte_flow_item_vxlan_gpe)),
MK_FLOW_ITEM(ARP_ETH_IPV4, sizeof(struct rte_flow_item_arp_eth_ipv4)),
@@ -66,6 +72,8 @@ static const struct rte_flow_desc_data rte_flow_desc_item[] = {
sizeof(struct rte_flow_item_icmp6_nd_opt_sla_eth)),
MK_FLOW_ITEM(ICMP6_ND_OPT_TLA_ETH,
sizeof(struct rte_flow_item_icmp6_nd_opt_tla_eth)),
+ MK_FLOW_ITEM(MARK, sizeof(struct rte_flow_item_mark)),
+ MK_FLOW_ITEM(META, sizeof(struct rte_flow_item_meta)),
};
/** Generate flow_action[] entry. */
@@ -80,6 +88,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
MK_FLOW_ACTION(END, 0),
MK_FLOW_ACTION(VOID, 0),
MK_FLOW_ACTION(PASSTHRU, 0),
+ MK_FLOW_ACTION(JUMP, sizeof(struct rte_flow_action_jump)),
MK_FLOW_ACTION(MARK, sizeof(struct rte_flow_action_mark)),
MK_FLOW_ACTION(FLAG, 0),
MK_FLOW_ACTION(QUEUE, sizeof(struct rte_flow_action_queue)),
@@ -90,6 +99,8 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
MK_FLOW_ACTION(VF, sizeof(struct rte_flow_action_vf)),
MK_FLOW_ACTION(PHY_PORT, sizeof(struct rte_flow_action_phy_port)),
MK_FLOW_ACTION(PORT_ID, sizeof(struct rte_flow_action_port_id)),
+ MK_FLOW_ACTION(METER, sizeof(struct rte_flow_action_meter)),
+ MK_FLOW_ACTION(SECURITY, sizeof(struct rte_flow_action_security)),
MK_FLOW_ACTION(OF_SET_MPLS_TTL,
sizeof(struct rte_flow_action_of_set_mpls_ttl)),
MK_FLOW_ACTION(OF_DEC_MPLS_TTL, 0),
@@ -109,6 +120,29 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = {
sizeof(struct rte_flow_action_of_pop_mpls)),
MK_FLOW_ACTION(OF_PUSH_MPLS,
sizeof(struct rte_flow_action_of_push_mpls)),
+ MK_FLOW_ACTION(VXLAN_ENCAP, sizeof(struct rte_flow_action_vxlan_encap)),
+ MK_FLOW_ACTION(VXLAN_DECAP, 0),
+ MK_FLOW_ACTION(NVGRE_ENCAP, sizeof(struct rte_flow_action_vxlan_encap)),
+ MK_FLOW_ACTION(NVGRE_DECAP, 0),
+ MK_FLOW_ACTION(RAW_ENCAP, sizeof(struct rte_flow_action_raw_encap)),
+ MK_FLOW_ACTION(RAW_DECAP, sizeof(struct rte_flow_action_raw_decap)),
+ MK_FLOW_ACTION(SET_IPV4_SRC,
+ sizeof(struct rte_flow_action_set_ipv4)),
+ MK_FLOW_ACTION(SET_IPV4_DST,
+ sizeof(struct rte_flow_action_set_ipv4)),
+ MK_FLOW_ACTION(SET_IPV6_SRC,
+ sizeof(struct rte_flow_action_set_ipv6)),
+ MK_FLOW_ACTION(SET_IPV6_DST,
+ sizeof(struct rte_flow_action_set_ipv6)),
+ MK_FLOW_ACTION(SET_TP_SRC,
+ sizeof(struct rte_flow_action_set_tp)),
+ MK_FLOW_ACTION(SET_TP_DST,
+ sizeof(struct rte_flow_action_set_tp)),
+ MK_FLOW_ACTION(MAC_SWAP, 0),
+ MK_FLOW_ACTION(DEC_TTL, 0),
+ MK_FLOW_ACTION(SET_TTL, sizeof(struct rte_flow_action_set_ttl)),
+ MK_FLOW_ACTION(SET_MAC_SRC, sizeof(struct rte_flow_action_set_mac)),
+ MK_FLOW_ACTION(SET_MAC_DST, sizeof(struct rte_flow_action_set_mac)),
};
static int
@@ -288,26 +322,41 @@ rte_flow_error_set(struct rte_flow_error *error,
}
/** Pattern item specification types. */
-enum item_spec_type {
- ITEM_SPEC,
- ITEM_LAST,
- ITEM_MASK,
+enum rte_flow_conv_item_spec_type {
+ RTE_FLOW_CONV_ITEM_SPEC,
+ RTE_FLOW_CONV_ITEM_LAST,
+ RTE_FLOW_CONV_ITEM_MASK,
};
-/** Compute storage space needed by item specification and copy it. */
+/**
+ * Copy pattern item specification.
+ *
+ * @param[out] buf
+ * Output buffer. Can be NULL if @p size is zero.
+ * @param size
+ * Size of @p buf in bytes.
+ * @param[in] item
+ * Pattern item to copy specification from.
+ * @param type
+ * Specification selector for either @p spec, @p last or @p mask.
+ *
+ * @return
+ * Number of bytes needed to store pattern item specification regardless
+ * of @p size. @p buf contents are truncated to @p size if not large
+ * enough.
+ */
static size_t
-flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
- enum item_spec_type type)
+rte_flow_conv_item_spec(void *buf, const size_t size,
+ const struct rte_flow_item *item,
+ enum rte_flow_conv_item_spec_type type)
{
- size_t size = 0;
+ size_t off;
const void *data =
- type == ITEM_SPEC ? item->spec :
- type == ITEM_LAST ? item->last :
- type == ITEM_MASK ? item->mask :
+ type == RTE_FLOW_CONV_ITEM_SPEC ? item->spec :
+ type == RTE_FLOW_CONV_ITEM_LAST ? item->last :
+ type == RTE_FLOW_CONV_ITEM_MASK ? item->mask :
NULL;
- if (!item->spec || !data)
- goto empty;
switch (item->type) {
union {
const struct rte_flow_item_raw *raw;
@@ -324,7 +373,7 @@ flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
union {
struct rte_flow_item_raw *raw;
} dst;
- size_t off;
+ size_t tmp;
case RTE_FLOW_ITEM_TYPE_RAW:
spec.raw = item->spec;
@@ -332,91 +381,466 @@ flow_item_spec_copy(void *buf, const struct rte_flow_item *item,
mask.raw = item->mask ? item->mask : &rte_flow_item_raw_mask;
src.raw = data;
dst.raw = buf;
- off = RTE_ALIGN_CEIL(sizeof(struct rte_flow_item_raw),
- sizeof(*src.raw->pattern));
- if (type == ITEM_SPEC ||
- (type == ITEM_MASK &&
+ rte_memcpy(dst.raw,
+ (&(struct rte_flow_item_raw){
+ .relative = src.raw->relative,
+ .search = src.raw->search,
+ .reserved = src.raw->reserved,
+ .offset = src.raw->offset,
+ .limit = src.raw->limit,
+ .length = src.raw->length,
+ }),
+ size > sizeof(*dst.raw) ? sizeof(*dst.raw) : size);
+ off = sizeof(*dst.raw);
+ if (type == RTE_FLOW_CONV_ITEM_SPEC ||
+ (type == RTE_FLOW_CONV_ITEM_MASK &&
((spec.raw->length & mask.raw->length) >=
(last.raw->length & mask.raw->length))))
- size = spec.raw->length & mask.raw->length;
+ tmp = spec.raw->length & mask.raw->length;
else
- size = last.raw->length & mask.raw->length;
- size = off + size * sizeof(*src.raw->pattern);
- if (dst.raw) {
- memcpy(dst.raw, src.raw, sizeof(*src.raw));
- dst.raw->pattern = memcpy((uint8_t *)dst.raw + off,
- src.raw->pattern,
- size - off);
+ tmp = last.raw->length & mask.raw->length;
+ if (tmp) {
+ off = RTE_ALIGN_CEIL(off, sizeof(*dst.raw->pattern));
+ if (size >= off + tmp)
+ dst.raw->pattern = rte_memcpy
+ ((void *)((uintptr_t)dst.raw + off),
+ src.raw->pattern, tmp);
+ off += tmp;
}
break;
default:
- size = rte_flow_desc_item[item->type].size;
- if (buf)
- memcpy(buf, data, size);
+ off = rte_flow_desc_item[item->type].size;
+ rte_memcpy(buf, data, (size > off ? off : size));
break;
}
-empty:
- return RTE_ALIGN_CEIL(size, sizeof(double));
+ return off;
}
-/** Compute storage space needed by action configuration and copy it. */
+/**
+ * Copy action configuration.
+ *
+ * @param[out] buf
+ * Output buffer. Can be NULL if @p size is zero.
+ * @param size
+ * Size of @p buf in bytes.
+ * @param[in] action
+ * Action to copy configuration from.
+ *
+ * @return
+ * Number of bytes needed to store pattern item specification regardless
+ * of @p size. @p buf contents are truncated to @p size if not large
+ * enough.
+ */
static size_t
-flow_action_conf_copy(void *buf, const struct rte_flow_action *action)
+rte_flow_conv_action_conf(void *buf, const size_t size,
+ const struct rte_flow_action *action)
{
- size_t size = 0;
+ size_t off;
- if (!action->conf)
- goto empty;
switch (action->type) {
union {
const struct rte_flow_action_rss *rss;
+ const struct rte_flow_action_vxlan_encap *vxlan_encap;
+ const struct rte_flow_action_nvgre_encap *nvgre_encap;
} src;
union {
struct rte_flow_action_rss *rss;
+ struct rte_flow_action_vxlan_encap *vxlan_encap;
+ struct rte_flow_action_nvgre_encap *nvgre_encap;
} dst;
- size_t off;
+ size_t tmp;
+ int ret;
case RTE_FLOW_ACTION_TYPE_RSS:
src.rss = action->conf;
dst.rss = buf;
- off = 0;
- if (dst.rss)
- *dst.rss = (struct rte_flow_action_rss){
+ rte_memcpy(dst.rss,
+ (&(struct rte_flow_action_rss){
.func = src.rss->func,
.level = src.rss->level,
.types = src.rss->types,
.key_len = src.rss->key_len,
.queue_num = src.rss->queue_num,
- };
- off += sizeof(*src.rss);
+ }),
+ size > sizeof(*dst.rss) ? sizeof(*dst.rss) : size);
+ off = sizeof(*dst.rss);
if (src.rss->key_len) {
- off = RTE_ALIGN_CEIL(off, sizeof(double));
- size = sizeof(*src.rss->key) * src.rss->key_len;
- if (dst.rss)
- dst.rss->key = memcpy
+ off = RTE_ALIGN_CEIL(off, sizeof(*dst.rss->key));
+ tmp = sizeof(*src.rss->key) * src.rss->key_len;
+ if (size >= off + tmp)
+ dst.rss->key = rte_memcpy
((void *)((uintptr_t)dst.rss + off),
- src.rss->key, size);
- off += size;
+ src.rss->key, tmp);
+ off += tmp;
}
if (src.rss->queue_num) {
- off = RTE_ALIGN_CEIL(off, sizeof(double));
- size = sizeof(*src.rss->queue) * src.rss->queue_num;
- if (dst.rss)
- dst.rss->queue = memcpy
+ off = RTE_ALIGN_CEIL(off, sizeof(*dst.rss->queue));
+ tmp = sizeof(*src.rss->queue) * src.rss->queue_num;
+ if (size >= off + tmp)
+ dst.rss->queue = rte_memcpy
((void *)((uintptr_t)dst.rss + off),
- src.rss->queue, size);
- off += size;
+ src.rss->queue, tmp);
+ off += tmp;
+ }
+ break;
+ case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+ case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+ src.vxlan_encap = action->conf;
+ dst.vxlan_encap = buf;
+ RTE_BUILD_BUG_ON(sizeof(*src.vxlan_encap) !=
+ sizeof(*src.nvgre_encap) ||
+ offsetof(struct rte_flow_action_vxlan_encap,
+ definition) !=
+ offsetof(struct rte_flow_action_nvgre_encap,
+ definition));
+ off = sizeof(*dst.vxlan_encap);
+ if (src.vxlan_encap->definition) {
+ off = RTE_ALIGN_CEIL
+ (off, sizeof(*dst.vxlan_encap->definition));
+ ret = rte_flow_conv
+ (RTE_FLOW_CONV_OP_PATTERN,
+ (void *)((uintptr_t)dst.vxlan_encap + off),
+ size > off ? size - off : 0,
+ src.vxlan_encap->definition, NULL);
+ if (ret < 0)
+ return 0;
+ if (size >= off + ret)
+ dst.vxlan_encap->definition =
+ (void *)((uintptr_t)dst.vxlan_encap +
+ off);
+ off += ret;
}
- size = off;
break;
default:
- size = rte_flow_desc_action[action->type].size;
- if (buf)
- memcpy(buf, action->conf, size);
+ off = rte_flow_desc_action[action->type].size;
+ rte_memcpy(buf, action->conf, (size > off ? off : size));
break;
}
-empty:
- return RTE_ALIGN_CEIL(size, sizeof(double));
+ return off;
+}
+
+/**
+ * Copy a list of pattern items.
+ *
+ * @param[out] dst
+ * Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ * Size of @p dst in bytes.
+ * @param[in] src
+ * Source pattern items.
+ * @param num
+ * Maximum number of pattern items to process from @p src or 0 to process
+ * the entire list. In both cases, processing stops after
+ * RTE_FLOW_ITEM_TYPE_END is encountered.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * A positive value representing the number of bytes needed to store
+ * pattern items regardless of @p size on success (@p buf contents are
+ * truncated to @p size if not large enough), a negative errno value
+ * otherwise and rte_errno is set.
+ */
+static int
+rte_flow_conv_pattern(struct rte_flow_item *dst,
+ const size_t size,
+ const struct rte_flow_item *src,
+ unsigned int num,
+ struct rte_flow_error *error)
+{
+ uintptr_t data = (uintptr_t)dst;
+ size_t off;
+ size_t ret;
+ unsigned int i;
+
+ for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
+ if ((size_t)src->type >= RTE_DIM(rte_flow_desc_item) ||
+ !rte_flow_desc_item[src->type].name)
+ return rte_flow_error_set
+ (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, src,
+ "cannot convert unknown item type");
+ if (size >= off + sizeof(*dst))
+ *dst = (struct rte_flow_item){
+ .type = src->type,
+ };
+ off += sizeof(*dst);
+ if (!src->type)
+ num = i + 1;
+ }
+ num = i;
+ src -= num;
+ dst -= num;
+ do {
+ if (src->spec) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ ret = rte_flow_conv_item_spec
+ ((void *)(data + off),
+ size > off ? size - off : 0, src,
+ RTE_FLOW_CONV_ITEM_SPEC);
+ if (size && size >= off + ret)
+ dst->spec = (void *)(data + off);
+ off += ret;
+
+ }
+ if (src->last) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ ret = rte_flow_conv_item_spec
+ ((void *)(data + off),
+ size > off ? size - off : 0, src,
+ RTE_FLOW_CONV_ITEM_LAST);
+ if (size && size >= off + ret)
+ dst->last = (void *)(data + off);
+ off += ret;
+ }
+ if (src->mask) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ ret = rte_flow_conv_item_spec
+ ((void *)(data + off),
+ size > off ? size - off : 0, src,
+ RTE_FLOW_CONV_ITEM_MASK);
+ if (size && size >= off + ret)
+ dst->mask = (void *)(data + off);
+ off += ret;
+ }
+ ++src;
+ ++dst;
+ } while (--num);
+ return off;
+}
+
+/**
+ * Copy a list of actions.
+ *
+ * @param[out] dst
+ * Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ * Size of @p dst in bytes.
+ * @param[in] src
+ * Source actions.
+ * @param num
+ * Maximum number of actions to process from @p src or 0 to process the
+ * entire list. In both cases, processing stops after
+ * RTE_FLOW_ACTION_TYPE_END is encountered.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * A positive value representing the number of bytes needed to store
+ * actions regardless of @p size on success (@p buf contents are truncated
+ * to @p size if not large enough), a negative errno value otherwise and
+ * rte_errno is set.
+ */
+static int
+rte_flow_conv_actions(struct rte_flow_action *dst,
+ const size_t size,
+ const struct rte_flow_action *src,
+ unsigned int num,
+ struct rte_flow_error *error)
+{
+ uintptr_t data = (uintptr_t)dst;
+ size_t off;
+ size_t ret;
+ unsigned int i;
+
+ for (i = 0, off = 0; !num || i != num; ++i, ++src, ++dst) {
+ if ((size_t)src->type >= RTE_DIM(rte_flow_desc_action) ||
+ !rte_flow_desc_action[src->type].name)
+ return rte_flow_error_set
+ (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
+ src, "cannot convert unknown action type");
+ if (size >= off + sizeof(*dst))
+ *dst = (struct rte_flow_action){
+ .type = src->type,
+ };
+ off += sizeof(*dst);
+ if (!src->type)
+ num = i + 1;
+ }
+ num = i;
+ src -= num;
+ dst -= num;
+ do {
+ if (src->conf) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ ret = rte_flow_conv_action_conf
+ ((void *)(data + off),
+ size > off ? size - off : 0, src);
+ if (size && size >= off + ret)
+ dst->conf = (void *)(data + off);
+ off += ret;
+ }
+ ++src;
+ ++dst;
+ } while (--num);
+ return off;
+}
+
+/**
+ * Copy flow rule components.
+ *
+ * This comprises the flow rule descriptor itself, attributes, pattern and
+ * actions list. NULL components in @p src are skipped.
+ *
+ * @param[out] dst
+ * Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ * Size of @p dst in bytes.
+ * @param[in] src
+ * Source flow rule descriptor.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * A positive value representing the number of bytes needed to store all
+ * components including the descriptor regardless of @p size on success
+ * (@p buf contents are truncated to @p size if not large enough), a
+ * negative errno value otherwise and rte_errno is set.
+ */
+static int
+rte_flow_conv_rule(struct rte_flow_conv_rule *dst,
+ const size_t size,
+ const struct rte_flow_conv_rule *src,
+ struct rte_flow_error *error)
+{
+ size_t off;
+ int ret;
+
+ rte_memcpy(dst,
+ (&(struct rte_flow_conv_rule){
+ .attr = NULL,
+ .pattern = NULL,
+ .actions = NULL,
+ }),
+ size > sizeof(*dst) ? sizeof(*dst) : size);
+ off = sizeof(*dst);
+ if (src->attr_ro) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ if (size && size >= off + sizeof(*dst->attr))
+ dst->attr = rte_memcpy
+ ((void *)((uintptr_t)dst + off),
+ src->attr_ro, sizeof(*dst->attr));
+ off += sizeof(*dst->attr);
+ }
+ if (src->pattern_ro) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ ret = rte_flow_conv_pattern((void *)((uintptr_t)dst + off),
+ size > off ? size - off : 0,
+ src->pattern_ro, 0, error);
+ if (ret < 0)
+ return ret;
+ if (size && size >= off + (size_t)ret)
+ dst->pattern = (void *)((uintptr_t)dst + off);
+ off += ret;
+ }
+ if (src->actions_ro) {
+ off = RTE_ALIGN_CEIL(off, sizeof(double));
+ ret = rte_flow_conv_actions((void *)((uintptr_t)dst + off),
+ size > off ? size - off : 0,
+ src->actions_ro, 0, error);
+ if (ret < 0)
+ return ret;
+ if (size >= off + (size_t)ret)
+ dst->actions = (void *)((uintptr_t)dst + off);
+ off += ret;
+ }
+ return off;
+}
+
+/**
+ * Retrieve the name of a pattern item/action type.
+ *
+ * @param is_action
+ * Nonzero when @p src represents an action type instead of a pattern item
+ * type.
+ * @param is_ptr
+ * Nonzero to write string address instead of contents into @p dst.
+ * @param[out] dst
+ * Destination buffer. Can be NULL if @p size is zero.
+ * @param size
+ * Size of @p dst in bytes.
+ * @param[in] src
+ * Depending on @p is_action, source pattern item or action type cast as a
+ * pointer.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * A positive value representing the number of bytes needed to store the
+ * name or its address regardless of @p size on success (@p buf contents
+ * are truncated to @p size if not large enough), a negative errno value
+ * otherwise and rte_errno is set.
+ */
+static int
+rte_flow_conv_name(int is_action,
+ int is_ptr,
+ char *dst,
+ const size_t size,
+ const void *src,
+ struct rte_flow_error *error)
+{
+ struct desc_info {
+ const struct rte_flow_desc_data *data;
+ size_t num;
+ };
+ static const struct desc_info info_rep[2] = {
+ { rte_flow_desc_item, RTE_DIM(rte_flow_desc_item), },
+ { rte_flow_desc_action, RTE_DIM(rte_flow_desc_action), },
+ };
+ const struct desc_info *const info = &info_rep[!!is_action];
+ unsigned int type = (uintptr_t)src;
+
+ if (type >= info->num)
+ return rte_flow_error_set
+ (error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "unknown object type to retrieve the name of");
+ if (!is_ptr)
+ return strlcpy(dst, info->data[type].name, size);
+ if (size >= sizeof(const char **))
+ *((const char **)dst) = info->data[type].name;
+ return sizeof(const char **);
+}
+
+/** Helper function to convert flow API objects. */
+int
+rte_flow_conv(enum rte_flow_conv_op op,
+ void *dst,
+ size_t size,
+ const void *src,
+ struct rte_flow_error *error)
+{
+ switch (op) {
+ const struct rte_flow_attr *attr;
+
+ case RTE_FLOW_CONV_OP_NONE:
+ return 0;
+ case RTE_FLOW_CONV_OP_ATTR:
+ attr = src;
+ if (size > sizeof(*attr))
+ size = sizeof(*attr);
+ rte_memcpy(dst, attr, size);
+ return sizeof(*attr);
+ case RTE_FLOW_CONV_OP_ITEM:
+ return rte_flow_conv_pattern(dst, size, src, 1, error);
+ case RTE_FLOW_CONV_OP_ACTION:
+ return rte_flow_conv_actions(dst, size, src, 1, error);
+ case RTE_FLOW_CONV_OP_PATTERN:
+ return rte_flow_conv_pattern(dst, size, src, 0, error);
+ case RTE_FLOW_CONV_OP_ACTIONS:
+ return rte_flow_conv_actions(dst, size, src, 0, error);
+ case RTE_FLOW_CONV_OP_RULE:
+ return rte_flow_conv_rule(dst, size, src, error);
+ case RTE_FLOW_CONV_OP_ITEM_NAME:
+ return rte_flow_conv_name(0, 0, dst, size, src, error);
+ case RTE_FLOW_CONV_OP_ACTION_NAME:
+ return rte_flow_conv_name(1, 0, dst, size, src, error);
+ case RTE_FLOW_CONV_OP_ITEM_NAME_PTR:
+ return rte_flow_conv_name(0, 1, dst, size, src, error);
+ case RTE_FLOW_CONV_OP_ACTION_NAME_PTR:
+ return rte_flow_conv_name(1, 1, dst, size, src, error);
+ }
+ return rte_flow_error_set
+ (error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+ "unknown object conversion operation");
}
/** Store a full rte_flow description. */
@@ -426,105 +850,49 @@ rte_flow_copy(struct rte_flow_desc *desc, size_t len,
const struct rte_flow_item *items,
const struct rte_flow_action *actions)
{
- struct rte_flow_desc *fd = NULL;
- size_t tmp;
- size_t off1 = 0;
- size_t off2 = 0;
- size_t size = 0;
-
-store:
- if (items) {
- const struct rte_flow_item *item;
-
- item = items;
- if (fd)
- fd->items = (void *)&fd->data[off1];
- do {
- struct rte_flow_item *dst = NULL;
-
- if ((size_t)item->type >=
- RTE_DIM(rte_flow_desc_item) ||
- !rte_flow_desc_item[item->type].name) {
- rte_errno = ENOTSUP;
- return 0;
- }
- if (fd)
- dst = memcpy(fd->data + off1, item,
- sizeof(*item));
- off1 += sizeof(*item);
- if (item->spec) {
- if (fd)
- dst->spec = fd->data + off2;
- off2 += flow_item_spec_copy
- (fd ? fd->data + off2 : NULL, item,
- ITEM_SPEC);
- }
- if (item->last) {
- if (fd)
- dst->last = fd->data + off2;
- off2 += flow_item_spec_copy
- (fd ? fd->data + off2 : NULL, item,
- ITEM_LAST);
- }
- if (item->mask) {
- if (fd)
- dst->mask = fd->data + off2;
- off2 += flow_item_spec_copy
- (fd ? fd->data + off2 : NULL, item,
- ITEM_MASK);
- }
- off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
- } while ((item++)->type != RTE_FLOW_ITEM_TYPE_END);
- off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
- }
- if (actions) {
- const struct rte_flow_action *action;
-
- action = actions;
- if (fd)
- fd->actions = (void *)&fd->data[off1];
- do {
- struct rte_flow_action *dst = NULL;
-
- if ((size_t)action->type >=
- RTE_DIM(rte_flow_desc_action) ||
- !rte_flow_desc_action[action->type].name) {
- rte_errno = ENOTSUP;
- return 0;
- }
- if (fd)
- dst = memcpy(fd->data + off1, action,
- sizeof(*action));
- off1 += sizeof(*action);
- if (action->conf) {
- if (fd)
- dst->conf = fd->data + off2;
- off2 += flow_action_conf_copy
- (fd ? fd->data + off2 : NULL, action);
- }
- off2 = RTE_ALIGN_CEIL(off2, sizeof(double));
- } while ((action++)->type != RTE_FLOW_ACTION_TYPE_END);
+ /*
+ * Overlap struct rte_flow_conv with struct rte_flow_desc in order
+ * to convert the former to the latter without wasting space.
+ */
+ struct rte_flow_conv_rule *dst =
+ len ?
+ (void *)((uintptr_t)desc +
+ (offsetof(struct rte_flow_desc, actions) -
+ offsetof(struct rte_flow_conv_rule, actions))) :
+ NULL;
+ size_t dst_size =
+ len > sizeof(*desc) - sizeof(*dst) ?
+ len - (sizeof(*desc) - sizeof(*dst)) :
+ 0;
+ struct rte_flow_conv_rule src = {
+ .attr_ro = NULL,
+ .pattern_ro = items,
+ .actions_ro = actions,
+ };
+ int ret;
+
+ RTE_BUILD_BUG_ON(sizeof(struct rte_flow_desc) <
+ sizeof(struct rte_flow_conv_rule));
+ if (dst_size &&
+ (&dst->pattern != &desc->items ||
+ &dst->actions != &desc->actions ||
+ (uintptr_t)(dst + 1) != (uintptr_t)(desc + 1))) {
+ rte_errno = EINVAL;
+ return 0;
}
- if (fd != NULL)
- return size;
- off1 = RTE_ALIGN_CEIL(off1, sizeof(double));
- tmp = RTE_ALIGN_CEIL(offsetof(struct rte_flow_desc, data),
- sizeof(double));
- size = tmp + off1 + off2;
- if (size > len)
- return size;
- fd = desc;
- if (fd != NULL) {
- *fd = (const struct rte_flow_desc) {
- .size = size,
+ ret = rte_flow_conv(RTE_FLOW_CONV_OP_RULE, dst, dst_size, &src, NULL);
+ if (ret < 0)
+ return 0;
+ ret += sizeof(*desc) - sizeof(*dst);
+ rte_memcpy(desc,
+ (&(struct rte_flow_desc){
+ .size = ret,
.attr = *attr,
- };
- tmp -= offsetof(struct rte_flow_desc, data);
- off2 = tmp + off1;
- off1 = tmp;
- goto store;
- }
- return 0;
+ .items = dst_size ? dst->pattern : NULL,
+ .actions = dst_size ? dst->actions : NULL,
+ }),
+ len > sizeof(*desc) ? sizeof(*desc) : len);
+ return ret;
}
/**
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index f8ba71cd..c0fe8792 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -18,6 +18,7 @@
#include <stdint.h>
#include <rte_arp.h>
+#include <rte_common.h>
#include <rte_ether.h>
#include <rte_eth_ctrl.h>
#include <rte_icmp.h>
@@ -413,6 +414,14 @@ enum rte_flow_item_type {
* See struct rte_flow_item_mark.
*/
RTE_FLOW_ITEM_TYPE_MARK,
+
+ /**
+ * [META]
+ *
+ * Matches a metadata value specified in mbuf metadata field.
+ * See struct rte_flow_item_meta.
+ */
+ RTE_FLOW_ITEM_TYPE_META,
};
/**
@@ -1156,6 +1165,22 @@ rte_flow_item_icmp6_nd_opt_tla_eth_mask = {
#endif
/**
+ * RTE_FLOW_ITEM_TYPE_META.
+ *
+ * Matches a specified metadata value.
+ */
+struct rte_flow_item_meta {
+ rte_be32_t data;
+};
+
+/** Default mask for RTE_FLOW_ITEM_TYPE_META. */
+#ifndef __cplusplus
+static const struct rte_flow_item_meta rte_flow_item_meta_mask = {
+ .data = RTE_BE32(UINT32_MAX),
+};
+#endif
+
+/**
* @warning
* @b EXPERIMENTAL: this structure may change without prior notice
*
@@ -1505,6 +1530,127 @@ enum rte_flow_action_type {
* error.
*/
RTE_FLOW_ACTION_TYPE_NVGRE_DECAP,
+
+ /**
+ * Add outer header whose template is provided in its data buffer
+ *
+ * See struct rte_flow_action_raw_encap.
+ */
+ RTE_FLOW_ACTION_TYPE_RAW_ENCAP,
+
+ /**
+ * Remove outer header whose template is provided in its data buffer.
+ *
+ * See struct rte_flow_action_raw_decap
+ */
+ RTE_FLOW_ACTION_TYPE_RAW_DECAP,
+
+ /**
+ * Modify IPv4 source address in the outermost IPv4 header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_IPV4,
+ * then the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_ipv4.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC,
+
+ /**
+ * Modify IPv4 destination address in the outermost IPv4 header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_IPV4,
+ * then the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_ipv4.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_IPV4_DST,
+
+ /**
+ * Modify IPv6 source address in the outermost IPv6 header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_IPV6,
+ * then the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_ipv6.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC,
+
+ /**
+ * Modify IPv6 destination address in the outermost IPv6 header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_IPV6,
+ * then the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_ipv6.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_IPV6_DST,
+
+ /**
+ * Modify source port number in the outermost TCP/UDP header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_TCP
+ * or RTE_FLOW_ITEM_TYPE_UDP, then the PMD should return a
+ * RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_tp.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_TP_SRC,
+
+ /**
+ * Modify destination port number in the outermost TCP/UDP header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_TCP
+ * or RTE_FLOW_ITEM_TYPE_UDP, then the PMD should return a
+ * RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_tp.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_TP_DST,
+
+ /**
+ * Swap the source and destination MAC addresses in the outermost
+ * Ethernet header.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_ETH,
+ * then the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * No associated configuration structure.
+ */
+ RTE_FLOW_ACTION_TYPE_MAC_SWAP,
+
+ /**
+ * Decrease TTL value directly
+ *
+ * No associated configuration structure.
+ */
+ RTE_FLOW_ACTION_TYPE_DEC_TTL,
+
+ /**
+ * Set TTL value
+ *
+ * See struct rte_flow_action_set_ttl
+ */
+ RTE_FLOW_ACTION_TYPE_SET_TTL,
+
+ /**
+ * Set source MAC address from matched flow.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_ETH,
+ * the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_mac.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_MAC_SRC,
+
+ /**
+ * Set destination MAC address from matched flow.
+ *
+ * If flow pattern does not define a valid RTE_FLOW_ITEM_TYPE_ETH,
+ * the PMD should return a RTE_FLOW_ERROR_TYPE_ACTION error.
+ *
+ * See struct rte_flow_action_set_mac.
+ */
+ RTE_FLOW_ACTION_TYPE_SET_MAC_DST,
};
/**
@@ -1868,6 +2014,114 @@ struct rte_flow_action_nvgre_encap {
struct rte_flow_item *definition;
};
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_RAW_ENCAP
+ *
+ * Raw tunnel end-point encapsulation data definition.
+ *
+ * The data holds the headers definitions to be applied on the packet.
+ * The data must start with ETH header up to the tunnel item header itself.
+ * When used right after RAW_DECAP (for decapsulating L3 tunnel type for
+ * example MPLSoGRE) the data will just hold layer 2 header.
+ *
+ * The preserve parameter holds which bits in the packet the PMD is not allowed
+ * to change, this parameter can also be NULL and then the PMD is allowed
+ * to update any field.
+ *
+ * size holds the number of bytes in @p data and @p preserve.
+ */
+struct rte_flow_action_raw_encap {
+ uint8_t *data; /**< Encapsulation data. */
+ uint8_t *preserve; /**< Bit-mask of @p data to preserve on output. */
+ size_t size; /**< Size of @p data and @p preserve. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_RAW_DECAP
+ *
+ * Raw tunnel end-point decapsulation data definition.
+ *
+ * The data holds the headers definitions to be removed from the packet.
+ * The data must start with ETH header up to the tunnel item header itself.
+ * When used right before RAW_DECAP (for encapsulating L3 tunnel type for
+ * example MPLSoGRE) the data will just hold layer 2 header.
+ *
+ * size holds the number of bytes in @p data.
+ */
+struct rte_flow_action_raw_decap {
+ uint8_t *data; /**< Encapsulation data. */
+ size_t size; /**< Size of @p data and @p preserve. */
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC
+ * RTE_FLOW_ACTION_TYPE_SET_IPV4_DST
+ *
+ * Allows modification of IPv4 source (RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC)
+ * and destination address (RTE_FLOW_ACTION_TYPE_SET_IPV4_DST) in the
+ * specified outermost IPv4 header.
+ */
+struct rte_flow_action_set_ipv4 {
+ rte_be32_t ipv4_addr;
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC
+ * RTE_FLOW_ACTION_TYPE_SET_IPV6_DST
+ *
+ * Allows modification of IPv6 source (RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC)
+ * and destination address (RTE_FLOW_ACTION_TYPE_SET_IPV6_DST) in the
+ * specified outermost IPv6 header.
+ */
+struct rte_flow_action_set_ipv6 {
+ uint8_t ipv6_addr[16];
+};
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_SET_TP_SRC
+ * RTE_FLOW_ACTION_TYPE_SET_TP_DST
+ *
+ * Allows modification of source (RTE_FLOW_ACTION_TYPE_SET_TP_SRC)
+ * and destination (RTE_FLOW_ACTION_TYPE_SET_TP_DST) port numbers
+ * in the specified outermost TCP/UDP header.
+ */
+struct rte_flow_action_set_tp {
+ rte_be16_t port;
+};
+
+/**
+ * RTE_FLOW_ACTION_TYPE_SET_TTL
+ *
+ * Set the TTL value directly for IPv4 or IPv6
+ */
+struct rte_flow_action_set_ttl {
+ uint8_t ttl_value;
+};
+
+/**
+ * RTE_FLOW_ACTION_TYPE_SET_MAC
+ *
+ * Set MAC address from the matched flow
+ */
+struct rte_flow_action_set_mac {
+ uint8_t mac_addr[ETHER_ADDR_LEN];
+};
+
/*
* Definition of a single action.
*
@@ -1932,6 +2186,175 @@ struct rte_flow_error {
};
/**
+ * Complete flow rule description.
+ *
+ * This object type is used when converting a flow rule description.
+ *
+ * @see RTE_FLOW_CONV_OP_RULE
+ * @see rte_flow_conv()
+ */
+RTE_STD_C11
+struct rte_flow_conv_rule {
+ union {
+ const struct rte_flow_attr *attr_ro; /**< RO attributes. */
+ struct rte_flow_attr *attr; /**< Attributes. */
+ };
+ union {
+ const struct rte_flow_item *pattern_ro; /**< RO pattern. */
+ struct rte_flow_item *pattern; /**< Pattern items. */
+ };
+ union {
+ const struct rte_flow_action *actions_ro; /**< RO actions. */
+ struct rte_flow_action *actions; /**< List of actions. */
+ };
+};
+
+/**
+ * Conversion operations for flow API objects.
+ *
+ * @see rte_flow_conv()
+ */
+enum rte_flow_conv_op {
+ /**
+ * No operation to perform.
+ *
+ * rte_flow_conv() simply returns 0.
+ */
+ RTE_FLOW_CONV_OP_NONE,
+
+ /**
+ * Convert attributes structure.
+ *
+ * This is a basic copy of an attributes structure.
+ *
+ * - @p src type:
+ * @code const struct rte_flow_attr * @endcode
+ * - @p dst type:
+ * @code struct rte_flow_attr * @endcode
+ */
+ RTE_FLOW_CONV_OP_ATTR,
+
+ /**
+ * Convert a single item.
+ *
+ * Duplicates @p spec, @p last and @p mask but not outside objects.
+ *
+ * - @p src type:
+ * @code const struct rte_flow_item * @endcode
+ * - @p dst type:
+ * @code struct rte_flow_item * @endcode
+ */
+ RTE_FLOW_CONV_OP_ITEM,
+
+ /**
+ * Convert a single action.
+ *
+ * Duplicates @p conf but not outside objects.
+ *
+ * - @p src type:
+ * @code const struct rte_flow_action * @endcode
+ * - @p dst type:
+ * @code struct rte_flow_action * @endcode
+ */
+ RTE_FLOW_CONV_OP_ACTION,
+
+ /**
+ * Convert an entire pattern.
+ *
+ * Duplicates all pattern items at once with the same constraints as
+ * RTE_FLOW_CONV_OP_ITEM.
+ *
+ * - @p src type:
+ * @code const struct rte_flow_item * @endcode
+ * - @p dst type:
+ * @code struct rte_flow_item * @endcode
+ */
+ RTE_FLOW_CONV_OP_PATTERN,
+
+ /**
+ * Convert a list of actions.
+ *
+ * Duplicates the entire list of actions at once with the same
+ * constraints as RTE_FLOW_CONV_OP_ACTION.
+ *
+ * - @p src type:
+ * @code const struct rte_flow_action * @endcode
+ * - @p dst type:
+ * @code struct rte_flow_action * @endcode
+ */
+ RTE_FLOW_CONV_OP_ACTIONS,
+
+ /**
+ * Convert a complete flow rule description.
+ *
+ * Comprises attributes, pattern and actions together at once with
+ * the usual constraints.
+ *
+ * - @p src type:
+ * @code const struct rte_flow_conv_rule * @endcode
+ * - @p dst type:
+ * @code struct rte_flow_conv_rule * @endcode
+ */
+ RTE_FLOW_CONV_OP_RULE,
+
+ /**
+ * Convert item type to its name string.
+ *
+ * Writes a NUL-terminated string to @p dst. Like snprintf(), the
+ * returned value excludes the terminator which is always written
+ * nonetheless.
+ *
+ * - @p src type:
+ * @code (const void *)enum rte_flow_item_type @endcode
+ * - @p dst type:
+ * @code char * @endcode
+ **/
+ RTE_FLOW_CONV_OP_ITEM_NAME,
+
+ /**
+ * Convert action type to its name string.
+ *
+ * Writes a NUL-terminated string to @p dst. Like snprintf(), the
+ * returned value excludes the terminator which is always written
+ * nonetheless.
+ *
+ * - @p src type:
+ * @code (const void *)enum rte_flow_action_type @endcode
+ * - @p dst type:
+ * @code char * @endcode
+ **/
+ RTE_FLOW_CONV_OP_ACTION_NAME,
+
+ /**
+ * Convert item type to pointer to item name.
+ *
+ * Retrieves item name pointer from its type. The string itself is
+ * not copied; instead, a unique pointer to an internal static
+ * constant storage is written to @p dst.
+ *
+ * - @p src type:
+ * @code (const void *)enum rte_flow_item_type @endcode
+ * - @p dst type:
+ * @code const char ** @endcode
+ */
+ RTE_FLOW_CONV_OP_ITEM_NAME_PTR,
+
+ /**
+ * Convert action type to pointer to action name.
+ *
+ * Retrieves action name pointer from its type. The string itself is
+ * not copied; instead, a unique pointer to an internal static
+ * constant storage is written to @p dst.
+ *
+ * - @p src type:
+ * @code (const void *)enum rte_flow_action_type @endcode
+ * - @p dst type:
+ * @code const char ** @endcode
+ */
+ RTE_FLOW_CONV_OP_ACTION_NAME_PTR,
+};
+
+/**
* Check whether a flow rule can be created on a given port.
*
* The flow rule is validated for correctness and whether it could be accepted
@@ -2162,10 +2585,8 @@ rte_flow_error_set(struct rte_flow_error *error,
const char *message);
/**
- * Generic flow representation.
- *
- * This form is sufficient to describe an rte_flow independently from any
- * PMD implementation and allows for replayability and identification.
+ * @deprecated
+ * @see rte_flow_copy()
*/
struct rte_flow_desc {
size_t size; /**< Allocated space including data[]. */
@@ -2176,8 +2597,14 @@ struct rte_flow_desc {
};
/**
+ * @deprecated
* Copy an rte_flow rule description.
*
+ * This interface is kept for compatibility with older applications but is
+ * implemented as a wrapper to rte_flow_conv(). It is deprecated due to its
+ * lack of flexibility and reliance on a type unusable with C++ programs
+ * (struct rte_flow_desc).
+ *
* @param[in] fd
* Flow rule description.
* @param[in] len
@@ -2195,12 +2622,61 @@ struct rte_flow_desc {
* If len is lower than the size of the flow, the number of bytes that would
* have been written to desc had it been sufficient. Nothing is written.
*/
+__rte_deprecated
size_t
rte_flow_copy(struct rte_flow_desc *fd, size_t len,
const struct rte_flow_attr *attr,
const struct rte_flow_item *items,
const struct rte_flow_action *actions);
+/**
+ * Flow object conversion helper.
+ *
+ * This function performs conversion of various flow API objects to a
+ * pre-allocated destination buffer. See enum rte_flow_conv_op for possible
+ * operations and details about each of them.
+ *
+ * Since destination buffer must be large enough, it works in a manner
+ * reminiscent of snprintf():
+ *
+ * - If @p size is 0, @p dst may be a NULL pointer, otherwise @p dst must be
+ * non-NULL.
+ * - If positive, the returned value represents the number of bytes needed
+ * to store the conversion of @p src to @p dst according to @p op
+ * regardless of the @p size parameter.
+ * - Since no more than @p size bytes can be written to @p dst, output is
+ * truncated and may be inconsistent when the returned value is larger
+ * than that.
+ * - In case of conversion error, a negative error code is returned and
+ * @p dst contents are unspecified.
+ *
+ * @param op
+ * Operation to perform, related to the object type of @p dst.
+ * @param[out] dst
+ * Destination buffer address. Must be suitably aligned by the caller.
+ * @param size
+ * Destination buffer size in bytes.
+ * @param[in] src
+ * Source object to copy. Depending on @p op, its type may differ from
+ * that of @p dst.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL. Initialized in case of
+ * error only.
+ *
+ * @return
+ * The number of bytes required to convert @p src to @p dst on success, a
+ * negative errno value otherwise and rte_errno is set.
+ *
+ * @see rte_flow_conv_op
+ */
+__rte_experimental
+int
+rte_flow_conv(enum rte_flow_conv_op op,
+ void *dst,
+ size_t size,
+ const void *src,
+ struct rte_flow_error *error);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_ethdev/rte_tm.h b/lib/librte_ethdev/rte_tm.h
index 955f02ff..646ef388 100644
--- a/lib/librte_ethdev/rte_tm.h
+++ b/lib/librte_ethdev/rte_tm.h
@@ -831,10 +831,10 @@ enum rte_tm_cman_mode {
*/
struct rte_tm_red_params {
/** Minimum queue threshold */
- uint32_t min_th;
+ uint64_t min_th;
/** Maximum queue threshold */
- uint32_t max_th;
+ uint64_t max_th;
/** Inverse of packet marking probability maximum value (maxp), i.e.
* maxp_inv = 1 / maxp