Hi, > -----Original Message----- > From: dev [mailto:dev-boun...@dpdk.org] On Behalf Of Qiming Yang > Sent: Thursday, June 20, 2019 1:35 PM > To: dev@dpdk.org > Cc: Yang, Qiming <qiming.y...@intel.com> > Subject: [dpdk-dev] [PATCH v3 2/3] net/ice: add generic flow API > > This patch adds ice_flow_create, ice_flow_destroy, > ice_flow_flush and ice_flow_validate support, > these are used to handle all the generic filters. > > Signed-off-by: Qiming Yang <qiming.y...@intel.com> > --- > drivers/net/ice/Makefile | 1 + > drivers/net/ice/ice_ethdev.c | 44 +++ > drivers/net/ice/ice_ethdev.h | 5 + > drivers/net/ice/ice_generic_flow.c | 682 > +++++++++++++++++++++++++++++++++++++ > drivers/net/ice/ice_generic_flow.h | 654 > +++++++++++++++++++++++++++++++++++ > drivers/net/ice/meson.build | 1 + > 6 files changed, 1387 insertions(+) > create mode 100644 drivers/net/ice/ice_generic_flow.c > create mode 100644 drivers/net/ice/ice_generic_flow.h > > diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile > index b10d826..32abeb6 100644 > --- a/drivers/net/ice/Makefile > +++ b/drivers/net/ice/Makefile > @@ -79,5 +79,6 @@ endif > ifeq ($(CC_AVX2_SUPPORT), 1) > SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_rxtx_vec_avx2.c > endif > +SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_generic_flow.c > > include $(RTE_SDK)/mk/rte.lib.mk > diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c > index a94aa7e..8ee06d1 100644 > --- a/drivers/net/ice/ice_ethdev.c > +++ b/drivers/net/ice/ice_ethdev.c > @@ -15,6 +15,7 @@ > #include "base/ice_dcb.h" > #include "ice_ethdev.h" > #include "ice_rxtx.h" > +#include "ice_switch_filter.h" > > #define ICE_MAX_QP_NUM "max_queue_pair_num" > #define ICE_DFLT_OUTER_TAG_TYPE ICE_AQ_VSI_OUTER_TAG_VLAN_9100 > @@ -83,6 +84,10 @@ static int ice_xstats_get(struct rte_eth_dev *dev, > static int ice_xstats_get_names(struct rte_eth_dev *dev, > struct rte_eth_xstat_name *xstats_names, > unsigned int limit); > +static int ice_dev_filter_ctrl(struct rte_eth_dev *dev, > + enum rte_filter_type filter_type, > + enum rte_filter_op filter_op, > + void *arg); > > static const struct rte_pci_id pci_id_ice_map[] = { > { RTE_PCI_DEVICE(ICE_INTEL_VENDOR_ID, > ICE_DEV_ID_E810C_BACKPLANE) }, > @@ -141,6 +146,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = { > .xstats_get = ice_xstats_get, > .xstats_get_names = ice_xstats_get_names, > .xstats_reset = ice_stats_reset, > + .filter_ctrl = ice_dev_filter_ctrl, > }; > > /* store statistics names and its offset in stats structure */ > @@ -1478,6 +1484,8 @@ ice_dev_init(struct rte_eth_dev *dev) > /* get base queue pairs index in the device */ > ice_base_queue_get(pf); > > + TAILQ_INIT(&pf->flow_list); > + > return 0; > > err_pf_setup: > @@ -1620,6 +1628,8 @@ ice_dev_uninit(struct rte_eth_dev *dev) > { > struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev); > struct rte_intr_handle *intr_handle = &pci_dev->intr_handle; > + struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private); > + struct rte_flow *p_flow; > > ice_dev_close(dev); > > @@ -1637,6 +1647,13 @@ ice_dev_uninit(struct rte_eth_dev *dev) > rte_intr_callback_unregister(intr_handle, > ice_interrupt_handler, dev); > > + /* Remove all flows */ > + while ((p_flow = TAILQ_FIRST(&pf->flow_list))) { > + TAILQ_REMOVE(&pf->flow_list, p_flow, node); > + ice_free_switch_filter_rule(p_flow->rule); > + rte_free(p_flow); > + } > + > return 0; > } > > @@ -3622,6 +3639,33 @@ static int ice_xstats_get_names(__rte_unused > struct rte_eth_dev *dev, > } > > static int > +ice_dev_filter_ctrl(struct rte_eth_dev *dev, > + enum rte_filter_type filter_type, > + enum rte_filter_op filter_op, > + void *arg) > +{ > + int ret = 0; > + > + if (!dev) > + return -EINVAL; > + > + switch (filter_type) { > + case RTE_ETH_FILTER_GENERIC: > + if (filter_op != RTE_ETH_FILTER_GET) > + return -EINVAL; > + *(const void **)arg = &ice_flow_ops; > + break; > + default: > + PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", > + filter_type); > + ret = -EINVAL; > + break; > + } > + > + return ret; > +} > + > +static int > ice_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, > struct rte_pci_device *pci_dev) > { > diff --git a/drivers/net/ice/ice_ethdev.h b/drivers/net/ice/ice_ethdev.h > index 50b966c..8a52239 100644 > --- a/drivers/net/ice/ice_ethdev.h > +++ b/drivers/net/ice/ice_ethdev.h > @@ -234,12 +234,16 @@ struct ice_vsi { > bool offset_loaded; > }; > > +extern const struct rte_flow_ops ice_flow_ops; > + > /* Struct to store flow created. */ > struct rte_flow { > TAILQ_ENTRY(rte_flow) node; > void *rule; > }; > > +TAILQ_HEAD(ice_flow_list, rte_flow); > + > struct ice_pf { > struct ice_adapter *adapter; /* The adapter this PF associate to */ > struct ice_vsi *main_vsi; /* pointer to main VSI structure */ > @@ -266,6 +270,7 @@ struct ice_pf { > struct ice_eth_stats internal_stats; > bool offset_loaded; > bool adapter_stopped; > + struct ice_flow_list flow_list; > }; > > /** > diff --git a/drivers/net/ice/ice_generic_flow.c > b/drivers/net/ice/ice_generic_flow.c > new file mode 100644 > index 0000000..c6fce88 > --- /dev/null > +++ b/drivers/net/ice/ice_generic_flow.c > @@ -0,0 +1,682 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(c) 2019 Intel Corporation > + */ > + > +#include <sys/queue.h> > +#include <stdio.h> > +#include <errno.h> > +#include <stdint.h> > +#include <string.h>
[...] > + /* Find a void item */ > + pe = ice_find_first_item(pb + 1, true); > + > + cpy_count = pe - pb; > + rte_memcpy(items, pb, sizeof(struct rte_flow_item) * > cpy_count); > + > + items += cpy_count; > + > + if (pe->type == RTE_FLOW_ITEM_TYPE_END) { > + pb = pe; No need to "pb = pe". > + break; > + } > + > + pb = pe + 1; > + } > + /* Copy the END item. */ > + rte_memcpy(items, pe, sizeof(struct rte_flow_item)); > +} > + > +/* Check if the pattern matches a supported item type array */ > +static bool > +ice_match_pattern(enum rte_flow_item_type *item_array, > + const struct rte_flow_item *pattern) > +{ > + const struct rte_flow_item *item = pattern; > + > + while ((*item_array == item->type) && [...] > + if (icmp6_mask->code || > + icmp6_mask->checksum) { > + rte_flow_error_set(error, EINVAL, > + > RTE_FLOW_ERROR_TYPE_ITEM, > + item, > + "Invalid ICMP6 mask"); > + return 0; > + } > + > + if (icmp6_mask->type == UINT8_MAX) > + input_set |= ICE_INSET_ICMP6; Indent. > + break; > + case RTE_FLOW_ITEM_TYPE_VXLAN: > + vxlan_spec = item->spec; > + vxlan_mask = item->mask; > + /* Check if VXLAN item is used to describe protocol. > + * If yes, both spec and mask should be NULL. > + * If no, both spec and mask shouldn't be NULL. > + */ > + if ((!vxlan_spec && vxlan_mask) || > + (vxlan_spec && !vxlan_mask)) { > + rte_flow_error_set(error, EINVAL, > + RTE_FLOW_ERROR_TYPE_ITEM, > + item, > + "Invalid VXLAN item"); > + return -rte_errno; I think you need to return 0 as above, since the caller will check (!field). > + } > + > + break; > + case RTE_FLOW_ITEM_TYPE_NVGRE: > + nvgre_spec = item->spec; > + nvgre_mask = item->mask; > + /* Check if VXLAN item is used to describe protocol. Typo: VXLAN->NVGRE > + * If yes, both spec and mask should be NULL. > + * If no, both spec and mask shouldn't be NULL. > + */ > + if ((!nvgre_spec && nvgre_mask) || > + (nvgre_spec && !nvgre_mask)) { > + rte_flow_error_set(error, EINVAL, > + RTE_FLOW_ERROR_TYPE_ITEM, > + item, > + "Invalid VXLAN item"); > + return -rte_errno; Ditto. > + } > + > + break; > + default: > + rte_flow_error_set(error, EINVAL, > + RTE_FLOW_ERROR_TYPE_ITEM, > + item, > + "Invalid mask no exist"); > + break; > + } > + } > + return input_set; > +} > + > +static int ice_flow_valid_inset(const struct rte_flow_item pattern[], > + uint64_t inset, struct rte_flow_error *error) > +{ > + uint64_t fields; > + > + /* get valid field */ > + fields = ice_get_flow_field(pattern, error); > + if ((!fields) || (fields && (!inset))) { Maybe the intention is to : fields & (~inset), checking if the user's input set exceeds support scope. > + rte_flow_error_set(error, EINVAL, > + RTE_FLOW_ERROR_TYPE_ITEM_SPEC, > + pattern, > + "Invalid input set"); > + return -rte_errno; > + } > + > + return 0; > +} > + > +static int ice_flow_valid_action(const struct rte_flow_action *actions, > + struct rte_flow_error *error) > +{ > + switch (actions->type) { > + case RTE_FLOW_ACTION_TYPE_QUEUE: > + break; > + case RTE_FLOW_ACTION_TYPE_DROP: > + break; > + default: [...] > + RTE_FLOW_ERROR_TYPE_HANDLE, NULL, > + "Failed to allocate memory"); > + return flow; > + } > + > + ret = ice_flow_validate(dev, attr, pattern, actions, error); > + if (ret < 0) > + return NULL; Goto free_flow BRs, Xiao > + > + ret = ice_create_switch_filter(pf, pattern, actions, flow, error); > + if (ret) > + goto free_flow; > + > + TAILQ_INSERT_TAIL(&pf->flow_list, flow, node); > + return flow; > + > +free_flow: > + rte_flow_error_set(error, -ret, > + RTE_FLOW_ERROR_TYPE_HANDLE, NULL, > + "Failed to create flow."); > + rte_free(flow); > + return NULL; > +} > + > +static int > +ice_flow_destroy(struct rte_eth_dev *dev, > + struct rte_flow *flow, > + struct rte_flow_error *error) > +{ > + struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private); > + int ret = 0; > + > + ret = ice_destroy_switch_filter(pf, flow, error); > + > + if (!ret) { > + TAILQ_REMOVE(&pf->flow_list, flow, node); > + rte_free(flow); > + } else > + rte_flow_error_set(error, -ret, > + RTE_FLOW_ERROR_TYPE_HANDLE, NULL, > + "Failed to destroy flow."); > + > + return ret; > +} > + > +static int > +ice_flow_flush(struct rte_eth_dev *dev, > + struct rte_flow_error *error) > +{ > + struct ice_pf *pf = ICE_DEV_PRIVATE_TO_PF(dev->data->dev_private); > + struct rte_flow *p_flow; > + int ret; > + > + TAILQ_FOREACH(p_flow, &pf->flow_list, node) { > + ret = ice_flow_destroy(dev, p_flow, error); > + if (ret) { > + rte_flow_error_set(error, -ret, > + RTE_FLOW_ERROR_TYPE_HANDLE, > NULL, > + "Failed to flush SW flows."); > + return -rte_errno; > + } > + } > + > + return ret; > +} > diff --git a/drivers/net/ice/ice_generic_flow.h > b/drivers/net/ice/ice_generic_flow.h > new file mode 100644 > index 0000000..ed7f3fe