diff options
author | Luca Boccassi <luca.boccassi@gmail.com> | 2018-11-01 11:59:50 +0000 |
---|---|---|
committer | Luca Boccassi <luca.boccassi@gmail.com> | 2018-11-01 12:00:19 +0000 |
commit | 8d01b9cd70a67cdafd5b965a70420c3bd7fb3f82 (patch) | |
tree | 208e3bc33c220854d89d010e3abf720a2e62e546 /lib/librte_ethdev | |
parent | b63264c8342e6a1b6971c79550d2af2024b6a4de (diff) |
New upstream version 18.11-rc1upstream/18.11-rc1
Change-Id: Iaa71986dd6332e878d8f4bf493101b2bbc6313bb
Signed-off-by: Luca Boccassi <luca.boccassi@gmail.com>
Diffstat (limited to 'lib/librte_ethdev')
-rw-r--r-- | lib/librte_ethdev/Makefile | 6 | ||||
-rw-r--r-- | lib/librte_ethdev/ethdev_private.c | 121 | ||||
-rw-r--r-- | lib/librte_ethdev/ethdev_private.h | 38 | ||||
-rw-r--r-- | lib/librte_ethdev/ethdev_profile.c | 103 | ||||
-rw-r--r-- | lib/librte_ethdev/ethdev_profile.h | 6 | ||||
-rw-r--r-- | lib/librte_ethdev/meson.build | 8 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_class_eth.c | 173 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_ethdev.c | 463 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_ethdev.h | 183 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_ethdev_core.h | 50 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_ethdev_driver.h | 37 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_ethdev_pci.h | 11 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_ethdev_version.map | 17 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_flow.c | 686 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_flow.h | 484 | ||||
-rw-r--r-- | lib/librte_ethdev/rte_tm.h | 4 |
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, + ð_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, - ð_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 |