Hi Beilei, On Wed, Dec 28, 2016 at 09:00:03AM +0000, Xing, Beilei wrote: > > > > -----Original Message----- > > From: Adrien Mazarguil [mailto:adrien.mazarg...@6wind.com] > > Sent: Tuesday, December 27, 2016 8:40 PM > > To: Xing, Beilei <beilei.x...@intel.com> > > Cc: Wu, Jingjing <jingjing...@intel.com>; Zhang, Helin > > <helin.zh...@intel.com>; dev@dpdk.org > > Subject: Re: [dpdk-dev] [PATCH v2 07/17] net/i40e: add flow validate > > function > > > > Hi Beilei, > > > > A few comments below. > > > > On Tue, Dec 27, 2016 at 02:26:14PM +0800, Beilei Xing wrote: > > > This patch adds i40e_flow_validation function to check if a flow is > > > valid according to the flow pattern. > > > i40e_parse_ethertype_filter is added first, it also gets the ethertype > > > info. > > > i40e_flow.c is added to handle all generic filter events. > > > > > > Signed-off-by: Beilei Xing <beilei.x...@intel.com> > > > --- > > > drivers/net/i40e/Makefile | 1 + > > > drivers/net/i40e/i40e_ethdev.c | 5 + > > > drivers/net/i40e/i40e_ethdev.h | 20 ++ > > > drivers/net/i40e/i40e_flow.c | 431 > > +++++++++++++++++++++++++++++++++++++++++ > > > 4 files changed, 457 insertions(+) > > > create mode 100644 drivers/net/i40e/i40e_flow.c > > [...] > > > diff --git a/drivers/net/i40e/i40e_flow.c > > > b/drivers/net/i40e/i40e_flow.c new file mode 100644 index > > > 0000000..bf451ef > > > --- /dev/null > > > +++ b/drivers/net/i40e/i40e_flow.c > > [...] > > > + if (ethertype_filter->queue >= pf->dev_data->nb_rx_queues) { > > > + rte_flow_error_set(error, EINVAL, > > > + RTE_FLOW_ERROR_TYPE_ACTION, > > > + NULL, "Invalid queue ID for" > > > + " ethertype_filter."); > > > > When setting an error type related to an existing object provided by the > > application, you should set the related cause pointer to a non-NULL value. > > In > > this particular case, retrieving the action object seems difficult so it can > > remain that way, however there are many places in this series where it can > > be done. > > OK, I got the meaning and usage of cause pointer now. Thanks for the > explaination. > > > > > > + return -EINVAL; > > > > While this is perfectly valid, you could also return -rte_errno to avoid > > duplicating EINVAL. > > Yes, agree. > > > > > [...] > > > + } > > > + if (ethertype_filter->ether_type == ETHER_TYPE_IPv4 || > > > + ethertype_filter->ether_type == ETHER_TYPE_IPv6) { > > > + rte_flow_error_set(error, ENOTSUP, > > > + RTE_FLOW_ERROR_TYPE_ITEM, > > > + NULL, "Unsupported ether_type in" > > > + " control packet filter."); > > > + return -ENOTSUP; > > > + } > > > + if (ethertype_filter->ether_type == ETHER_TYPE_VLAN) > > > + PMD_DRV_LOG(WARNING, "filter vlan ether_type in" > > > + " first tag is not supported."); > > > + > > > + return ret; > > > +} > > [...] > > > +/* Parse attributes */ > > > +static int > > > +i40e_parse_attr(const struct rte_flow_attr *attr, > > > + struct rte_flow_error *error) > > > +{ > > > + /* Must be input direction */ > > > + if (!attr->ingress) { > > > + rte_flow_error_set(error, EINVAL, > > > + RTE_FLOW_ERROR_TYPE_ATTR_INGRESS, > > > + NULL, "Only support ingress."); > > > > Regarding my previous comment, &attr could replace NULL here as well as in > > subsequent calls to rte_flow_error_set(). > > Got it, thanks. > > > > > > + return -EINVAL; > > > + } > > > + > > > + /* Not supported */ > > > + if (attr->egress) { > > > + rte_flow_error_set(error, EINVAL, > > > + RTE_FLOW_ERROR_TYPE_ATTR_EGRESS, > > > + NULL, "Not support egress."); > > > + return -EINVAL; > > > + } > > > + > > > + /* Not supported */ > > > + if (attr->priority) { > > > + rte_flow_error_set(error, EINVAL, > > > + RTE_FLOW_ERROR_TYPE_ATTR_PRIORITY, > > > + NULL, "Not support priority."); > > > + return -EINVAL; > > > + } > > > + > > > + /* Not supported */ > > > + if (attr->group) { > > > + rte_flow_error_set(error, EINVAL, > > > + RTE_FLOW_ERROR_TYPE_ATTR_GROUP, > > > + NULL, "Not support group."); > > > + return -EINVAL; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int > > > +i40e_parse_ethertype_pattern(const struct rte_flow_item *pattern, > > > + struct rte_flow_error *error, > > > + struct rte_eth_ethertype_filter *filter) { > > > + const struct rte_flow_item *item = pattern; > > > + const struct rte_flow_item_eth *eth_spec; > > > + const struct rte_flow_item_eth *eth_mask; > > > + enum rte_flow_item_type item_type; > > > + > > > + for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { > > > + item_type = item->type; > > > + switch (item_type) { > > > + case RTE_FLOW_ITEM_TYPE_ETH: > > > + eth_spec = (const struct rte_flow_item_eth *)item- > > >spec; > > > + eth_mask = (const struct rte_flow_item_eth *)item- > > >mask; > > > + /* Get the MAC info. */ > > > + if (!eth_spec || !eth_mask) { > > > + rte_flow_error_set(error, EINVAL, > > > + > > RTE_FLOW_ERROR_TYPE_ITEM, > > > + NULL, > > > + "NULL ETH spec/mask"); > > > + return -EINVAL; > > > + } > > > > While optional, I think you should allow eth_spec and eth_mask to be NULL > > here as described in [1]: > > > > - If eth_spec is NULL, you can match anything that looks like a valid > > Ethernet header. > > > > - If eth_mask is NULL, you should assume a default mask (for Ethernet it > > usually means matching source/destination MACs perfectly). > > > > - You must check the "last" field as well, if non-NULL it may probably be > > supported as long as the following condition is satisfied: > > > > (spec & mask) == (last & mask) > > > > [1] http://dpdk.org/doc/guides/prog_guide/rte_flow.html#pattern-item > > > > Thanks for the specification. In fact, we don't support the "last" for both > ixgbe and i40e currently according to the original design, so we only support > perfect match till now. We will support it in the future, as the deadline is > coming, what do you think?
If you want to handle it later it's fine, however in that case you need to at least generate an error when last is non-NULL (I did not see such a check in this code). Note that supporting it properly as defined in the API could be relatively easy by implementing the above condition, it's just a small step above simply checking for a NULL value. > > [...] > > > + const struct rte_flow_action_queue *act_q; > > > + uint32_t index = 0; > > > + > > > + /* Check if the first non-void action is QUEUE or DROP. */ > > > + NEXT_ITEM_OF_ACTION(act, actions, index); > > > + if (act->type != RTE_FLOW_ACTION_TYPE_QUEUE && > > > + act->type != RTE_FLOW_ACTION_TYPE_DROP) { > > > + rte_flow_error_set(error, EINVAL, > > RTE_FLOW_ERROR_TYPE_ACTION, > > > + NULL, "Not supported action."); > > > > Again, you could report &act instead of NULL here (please check all > > remaining > > calls to rte_flow_error_set()). > > > > [...] > > > > -- > > Adrien Mazarguil > > 6WIND -- Adrien Mazarguil 6WIND