Thanks for your comments,

I will start working on V3

Ori

> -----Original Message-----
> From: Andrew Rybchenko <arybche...@solarflare.com>
> Sent: Monday, October 14, 2019 12:37 PM
> To: Ori Kam <or...@mellanox.com>; Thomas Monjalon
> <tho...@monjalon.net>; Ferruh Yigit <ferruh.yi...@intel.com>
> Cc: dev@dpdk.org; jingjing...@intel.com; step...@networkplumber.org
> Subject: Re: [PATCH v2 01/14] ethdev: add support for hairpin queue
> 
> Hi Ori,
> 
> see my answers below.
> 
> On 10/11/19 12:07 AM, Ori Kam wrote:
> > Hi Andrew,
> >
> > Thanks for your comments,
> >
> > PSB,
> > Ori
> >
> >> -----Original Message-----
> >> From: Andrew Rybchenko <arybche...@solarflare.com>
> >> Sent: Tuesday, October 8, 2019 7:11 PM
> >> To: Ori Kam <or...@mellanox.com>; Thomas Monjalon
> >> <tho...@monjalon.net>; Ferruh Yigit <ferruh.yi...@intel.com>
> >> Cc: dev@dpdk.org; jingjing...@intel.com; step...@networkplumber.org
> >> Subject: Re: [PATCH v2 01/14] ethdev: add support for hairpin queue
> >>
> >> Hi Ori,
> >>
> >> thanks for updated version. See my notes below.
> >>
> >> There are few style notes about line breaks which are not defined in
> >> coding style. Of course, it may be ignored.
> >>
> > I will fix what I can.
> >
> >> On 10/4/19 10:54 PM, Ori Kam wrote:
> >>> This commit introduce hairpin queue type.
> >>>
> >>> The hairpin queue in build from Rx queue binded to Tx queue.
> >>> It is used to offload traffic coming from the wire and redirect it back
> >>> to the wire.
> >>>
> >>> There are 3 new functions:
> >>> - rte_eth_dev_hairpin_capability_get
> >>> - rte_eth_rx_hairpin_queue_setup
> >>> - rte_eth_tx_hairpin_queue_setup
> >>>
> >>> In order to use the queue, there is a need to create rte_flow
> >>> with queue / RSS action that targets one or more of the Rx queues.
> >>>
> >>> Signed-off-by: Ori Kam <or...@mellanox.com>
> >> rte_eth_dev_[rt]x_queue_stop() should return error if used for hairpin
> >> queue.
> >> Right now rte_eth_dev_[rt]x_queue_start() will return 0. Not sure about it.
> >> What about rte_eth_rx_queue_info_get() and rte_eth_tx_queue_info_get()?
> >> Any other Rx/Tx queue functions?
> >>
> > I will add error to both functions (Tx/Rx)
> > I don't see any other function (only the info_get and queue_stop)
> >
> >>> ---
> >>> V2:
> >>>    - update according to ML comments.
> >>>
> >>> ---
> >>>    lib/librte_ethdev/rte_ethdev.c           | 214
> >> ++++++++++++++++++++++++++++++-
> >>>    lib/librte_ethdev/rte_ethdev.h           | 126 ++++++++++++++++++
> >>>    lib/librte_ethdev/rte_ethdev_core.h      |  27 +++-
> >>>    lib/librte_ethdev/rte_ethdev_version.map |   5 +
> >>>    4 files changed, 368 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/lib/librte_ethdev/rte_ethdev.c 
> >>> b/lib/librte_ethdev/rte_ethdev.c
> >>> index af82360..ee8af42 100644
> >>> --- a/lib/librte_ethdev/rte_ethdev.c
> >>> +++ b/lib/librte_ethdev/rte_ethdev.c
> >>> @@ -1752,12 +1752,102 @@ struct rte_eth_dev *
> >>>                   if (!dev->data->min_rx_buf_size ||
> >>>                       dev->data->min_rx_buf_size > mbp_buf_size)
> >>>                           dev->data->min_rx_buf_size = mbp_buf_size;
> >>> +         if (dev->data->rx_queue_state[rx_queue_id] ==
> >>> +             RTE_ETH_QUEUE_STATE_HAIRPIN)
> >>> +                 dev->data->rx_queue_state[rx_queue_id] =
> >>> +                         RTE_ETH_QUEUE_STATE_STOPPED;
> >> I don't understand it. Why is rte_eth_rx_queue_setup() changed?
> >>
> > This was done so user can reset the queue back to normal queue.
> 
> I think it should be done in queue release.
> 
> >>>           }
> >>>
> >>>           return eth_err(port_id, ret);
> >>>    }
> >>>
> >>>    int
> >>> +rte_eth_rx_hairpin_queue_setup(uint16_t port_id, uint16_t rx_queue_id,
> >>> +                        uint16_t nb_rx_desc,
> >>> +                        const struct rte_eth_hairpin_conf *conf)
> >>> +{
> >>> + int ret;
> >>> + struct rte_eth_dev *dev;
> >>> + struct rte_eth_hairpin_cap cap;
> >>> + struct rte_eth_dev_info dev_info;
> >>> + void **rxq;
> >>> + int i;
> >>> + int count = 0;
> >>> +
> >>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
> >>> +
> >>> + dev = &rte_eth_devices[port_id];
> >>> + if (rx_queue_id >= dev->data->nb_rx_queues) {
> >>> +         RTE_ETHDEV_LOG(ERR, "Invalid RX queue_id=%u\n",
> >> rx_queue_id);
> >>> +         return -EINVAL;
> >>> + }
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
> >> ENOTSUP);
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_cap_get,
> >>> +                         -ENOTSUP);
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >>> rx_hairpin_queue_setup,
> >>> +                         -ENOTSUP);
> >>> + rte_eth_dev_hairpin_capability_get(port_id, &cap);
> >> Return value should be checked. It makesĀ  hairpin_cap_get check above
> >> unnecessary.
> >>
> > I will add a check.
> >
> >>> + /* Use default specified by driver, if nb_rx_desc is zero */
> >>> + if (nb_rx_desc == 0)
> >>> +         nb_rx_desc = cap.max_nb_desc;
> >>> + if (nb_rx_desc > cap.max_nb_desc) {
> >>> +         RTE_ETHDEV_LOG(ERR,
> >>> +                        "Invalid value for nb_rx_desc(=%hu), should be: "
> >>> +                        "<= %hu", nb_rx_desc, cap.max_nb_desc);
> >>> +         return -EINVAL;
> >>> + }
> >>> + ret = rte_eth_dev_info_get(port_id, &dev_info);
> >>> + if (ret != 0)
> >>> +         return ret;
> >>> + if (dev->data->dev_started &&
> >>> +         !(dev_info.dev_capa &
> >>> +           RTE_ETH_DEV_CAPA_RUNTIME_RX_QUEUE_SETUP))
> >>> +         return -EBUSY;
> >>> + if (dev->data->dev_started &&
> >>> +         (dev->data->rx_queue_state[rx_queue_id] !=
> >>> +          RTE_ETH_QUEUE_STATE_STOPPED))
> >>> +         return -EBUSY;
> >>> + if (conf->peer_n > cap.max_rx_2_tx) {
> >>> +         RTE_ETHDEV_LOG(ERR,
> >>> +                        "Invalid value for number of peers(=%hu), "
> >>> +                        "should be: <= %hu", conf->peer_n,
> >>> +                        cap.max_rx_2_tx);
> >>> +         return -EINVAL;
> >>> + }
> >>> + if (conf->peer_n == 0) {
> >>> +         RTE_ETHDEV_LOG(ERR,
> >>> +                        "Invalid value for number of peers(=%hu), "
> >>> +                        "should be: > 0", conf->peer_n);
> >>> +         return -EINVAL;
> >>> + }
> >>> + if (cap.max_n_queues != -1) {
> >>> +         for (i = 0; i < dev->data->nb_rx_queues; i++) {
> >>> +                 if (dev->data->rx_queue_state[i] ==
> >>> +                     RTE_ETH_QUEUE_STATE_HAIRPIN)
> >>> +                         count++;
> >>> +         }
> >>> +         if (count > cap.max_n_queues) {
> >>> +                 RTE_ETHDEV_LOG(ERR,
> >>> +                                "To many Rx hairpin queues %d", count);
> >>> +                 return -EINVAL;
> >>> +         }
> >>> + }
> >>> + rxq = dev->data->rx_queues;
> >>> + if (rxq[rx_queue_id]) {
> >> Please, compare with NULL (I know that rte_eth_rx_queue_setup() does
> >> like above).
> >>
> > O.K. I will change, but may I ask why? If in the rte_eth_rx_queue_setup
> function it is written the same way,
> > why do you want this change?
> 
> https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdoc.dpdk.
> org%2Fguides%2Fcontributing%2Fcoding_style.html%23null-
> pointers&amp;data=02%7C01%7Corika%40mellanox.com%7C022cd953964f4a2
> 0d50508d7508a259f%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C
> 637066426584029629&amp;sdata=IBOo6AyTGn4DiNLHBCC5MbwJkRuqdsGqdrl
> vm0xS9Vw%3D&amp;reserved=0
> 


Thanks,

> >>> +         RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >>> rx_queue_release,
> >>> +                                 -ENOTSUP);
> >>> +         (*dev->dev_ops->rx_queue_release)(rxq[rx_queue_id]);
> >>> +         rxq[rx_queue_id] = NULL;
> >>> + }
> >>> + ret = (*dev->dev_ops->rx_hairpin_queue_setup)(dev, rx_queue_id,
> >>> +                                               nb_rx_desc, conf);
> >>> + if (!ret)
> >> Please, compare with 0
> >>
> > Will do, but again just for my knowledge why?
> 
> https://eur03.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdoc.dpdk.
> org%2Fguides%2Fcontributing%2Fcoding_style.html%23function-
> calls&amp;data=02%7C01%7Corika%40mellanox.com%7C022cd953964f4a20d5
> 0508d7508a259f%7Ca652971c7d2e4d9ba6a4d149256f461b%7C0%7C0%7C637
> 066426584029629&amp;sdata=G8ZxEWFFsv1kLWc6L7sKT8O6CSiBcj5ZuwQqmK
> 0Q6nY%3D&amp;reserved=0
> 

Thanks,

> >>> +         dev->data->rx_queue_state[rx_queue_id] =
> >>> +                 RTE_ETH_QUEUE_STATE_HAIRPIN;
> >>> + return eth_err(port_id, ret);
> >>> +}
> >>> +
> >>> +int
> >>>    rte_eth_tx_queue_setup(uint16_t port_id, uint16_t tx_queue_id,
> >>>                          uint16_t nb_tx_desc, unsigned int socket_id,
> >>>                          const struct rte_eth_txconf *tx_conf)
> >>> @@ -1851,9 +1941,97 @@ struct rte_eth_dev *
> >>>                           __func__);
> >>>                   return -EINVAL;
> >>>           }
> >>> + ret = (*dev->dev_ops->tx_queue_setup)(dev, tx_queue_id, nb_tx_desc,
> >>> +                                       socket_id, &local_conf);
> >>> + if (!ret)
> >>> +         if (dev->data->tx_queue_state[tx_queue_id] ==
> >>> +             RTE_ETH_QUEUE_STATE_HAIRPIN)
> >>> +                 dev->data->tx_queue_state[tx_queue_id] =
> >>> +                         RTE_ETH_QUEUE_STATE_STOPPED;
> >> Why is it changed?
> >>
> > Like in the Rx to enable switching back to normal queue.
> >
> >>> + return eth_err(port_id, ret);
> >>> +}
> >>> +
> >>> +int
> >>> +rte_eth_tx_hairpin_queue_setup(uint16_t port_id, uint16_t tx_queue_id,
> >>> +                        uint16_t nb_tx_desc,
> >>> +                        const struct rte_eth_hairpin_conf *conf)
> >>> +{
> >>> + struct rte_eth_dev *dev;
> >>> + struct rte_eth_hairpin_cap cap;
> >>> + struct rte_eth_dev_info dev_info;
> >>> + void **txq;
> >>> + int i;
> >>> + int count = 0;
> >>> + int ret;
> >>>
> >>> - return eth_err(port_id, (*dev->dev_ops->tx_queue_setup)(dev,
> >>> -                tx_queue_id, nb_tx_desc, socket_id, &local_conf));
> >>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
> >>> + dev = &rte_eth_devices[port_id];
> >>> + if (tx_queue_id >= dev->data->nb_tx_queues) {
> >>> +         RTE_ETHDEV_LOG(ERR, "Invalid TX queue_id=%u\n",
> >> tx_queue_id);
> >>> +         return -EINVAL;
> >>> + }
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -
> >> ENOTSUP);
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_cap_get,
> >>> +                         -ENOTSUP);
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >>> tx_hairpin_queue_setup,
> >>> +                         -ENOTSUP);
> >>> + rte_eth_dev_info_get(port_id, &dev_info);
> >> return value should be checked.
> >>
> >>> + rte_eth_dev_hairpin_capability_get(port_id, &cap);
> >> Check return value and you can rely onĀ  hairpin_cap_get check inside.
> >>
> > Same as above I will add a check but I'm not sure I understand the second
> part
> > Just to make sure I understand, you are talking about that if I don't check
> > the return value I'm not allowed to check the cap right?
> 
> It is about dev_ops->hairpin_cap_get vs NULL check.
> It is checked inside rte_eth_dev_hairpin_capability_get() and we should
> not duplicate the check above.
> 

O.K.

> >>> + /* Use default specified by driver, if nb_tx_desc is zero */
> >>> + if (nb_tx_desc == 0)
> >>> +         nb_tx_desc = cap.max_nb_desc;
> >>> + if (nb_tx_desc > cap.max_nb_desc) {
> >>> +         RTE_ETHDEV_LOG(ERR,
> >>> +                        "Invalid value for nb_tx_desc(=%hu), should be: "
> >>> +                        "<= %hu", nb_tx_desc, cap.max_nb_desc);
> >>> +         return -EINVAL;
> >>> + }
> >>> + if (conf->peer_n > cap.max_tx_2_rx) {
> >>> +         RTE_ETHDEV_LOG(ERR,
> >>> +                        "Invalid value for number of peers(=%hu), "
> >>> +                        "should be: <= %hu", conf->peer_n,
> >>> +                        cap.max_tx_2_rx);
> >>> +         return -EINVAL;
> >>> + }
> >>> + if (conf->peer_n == 0) {
> >>> +         RTE_ETHDEV_LOG(ERR,
> >>> +                        "Invalid value for number of peers(=%hu), "
> >>> +                        "should be: > 0", conf->peer_n);
> >>> +         return -EINVAL;
> >>> + }
> >>> + if (cap.max_n_queues != -1) {
> >>> +         for (i = 0; i < dev->data->nb_tx_queues; i++) {
> >>> +                 if (dev->data->tx_queue_state[i] ==
> >>> +                     RTE_ETH_QUEUE_STATE_HAIRPIN)
> >>> +                         count++;
> >>> +         }
> >>> +         if (count > cap.max_n_queues) {
> >>> +                 RTE_ETHDEV_LOG(ERR,
> >>> +                                "To many Rx hairpin queues %d", count);
> >>> +                 return -EINVAL;
> >>> +         }
> >>> + }
> >>> + if (dev->data->dev_started &&
> >>> +         !(dev_info.dev_capa &
> >>> +           RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP))
> >>> +         return -EBUSY;
> >>> + if (dev->data->dev_started &&
> >>> +         (dev->data->tx_queue_state[tx_queue_id] !=
> >>> +          RTE_ETH_QUEUE_STATE_STOPPED))
> >>> +         return -EBUSY;
> >>> + txq = dev->data->tx_queues;
> >>> + if (txq[tx_queue_id]) {
> >> Please, compare with NULL
> >>
> > O.K.
> >
> >>> +         RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops-
> >>> tx_queue_release,
> >>> +                                 -ENOTSUP);
> >>> +         (*dev->dev_ops->tx_queue_release)(txq[tx_queue_id]);
> >>> +         txq[tx_queue_id] = NULL;
> >>> + }
> >>> + ret = (*dev->dev_ops->tx_hairpin_queue_setup)
> >>> +         (dev, tx_queue_id, nb_tx_desc, conf);
> >>> + if (!ret)
> >> Please, compare with 0
> >>
> > O.K.
> >
> >>> +         dev->data->tx_queue_state[tx_queue_id] =
> >>> +                 RTE_ETH_QUEUE_STATE_HAIRPIN;
> >>> + return eth_err(port_id, ret);
> >>>    }
> >>>
> >>>    void
> >>> @@ -3981,12 +4159,20 @@ int rte_eth_set_queue_rate_limit(uint16_t
> >> port_id, uint16_t queue_idx,
> >>>           rte_errno = ENOTSUP;
> >>>           return NULL;
> >>>    #endif
> >>> + struct rte_eth_dev *dev;
> >>> +
> >>>           /* check input parameters */
> >>>           if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
> >>>                       queue_id >= 
> >>> rte_eth_devices[port_id].data->nb_rx_queues) {
> >>>                   rte_errno = EINVAL;
> >>>                   return NULL;
> >>>           }
> >>> + dev = &rte_eth_devices[port_id];
> >>> + if (dev->data->rx_queue_state[queue_id] ==
> >>> +     RTE_ETH_QUEUE_STATE_HAIRPIN) {
> >> It looks like line break is not required above. Just to make code a bit
> >> shorter.
> >>
> > Will fix if possible.
> >
> >>> +         rte_errno = EINVAL;
> >>> +         return NULL;
> >>> + }
> >>>           struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, 
> >>> sizeof(*cb), 0);
> >>>
> >>>           if (cb == NULL) {
> >>> @@ -4058,6 +4244,8 @@ int rte_eth_set_queue_rate_limit(uint16_t
> port_id,
> >> uint16_t queue_idx,
> >>>           rte_errno = ENOTSUP;
> >>>           return NULL;
> >>>    #endif
> >>> + struct rte_eth_dev *dev;
> >>> +
> >>>           /* check input parameters */
> >>>           if (!rte_eth_dev_is_valid_port(port_id) || fn == NULL ||
> >>>                       queue_id >= 
> >>> rte_eth_devices[port_id].data->nb_tx_queues) {
> >>> @@ -4065,6 +4253,13 @@ int rte_eth_set_queue_rate_limit(uint16_t
> >> port_id, uint16_t queue_idx,
> >>>                   return NULL;
> >>>           }
> >>>
> >>> + dev = &rte_eth_devices[port_id];
> >>> + if (dev->data->tx_queue_state[queue_id] ==
> >>> +     RTE_ETH_QUEUE_STATE_HAIRPIN) {
> >> It looks like line break is not required above. Just to make code a bit
> >> shorter.
> >>
> > Will fix.
> >
> >>> +         rte_errno = EINVAL;
> >>> +         return NULL;
> >>> + }
> >>> +
> >>>           struct rte_eth_rxtx_callback *cb = rte_zmalloc(NULL, 
> >>> sizeof(*cb), 0);
> >>>
> >>>           if (cb == NULL) {
> >>> @@ -4510,6 +4705,21 @@ int rte_eth_set_queue_rate_limit(uint16_t
> >> port_id, uint16_t queue_idx,
> >>>    }
> >>>
> >>>    int
> >>> +rte_eth_dev_hairpin_capability_get(uint16_t port_id,
> >>> +                            struct rte_eth_hairpin_cap *cap)
> >>> +{
> >>> + struct rte_eth_dev *dev;
> >>> +
> >>> + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
> >>> +
> >>> + dev = &rte_eth_devices[port_id];
> >>> + RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->hairpin_cap_get,
> >>> +                         -ENOTSUP);
> >> I think it would be useful to memset() cap with 0 to be sure that it is
> >> initialized.
> >>
> > O.K but if we follow your comments from above, the result is not valid if we
> return
> > error, so it is not a must, but like I said I don't care to add it.
> >
> >>> + return eth_err(port_id, (*dev->dev_ops->hairpin_cap_get)
> >>> +                (dev, cap));
> >>
> >> Please, consider to avoid line breaks above to make code a bit shorter.
> >> Of course, it should not exceed line length limit.
> >>
> > Will check.
> >
> >>> +}
> >>> +
> >>> +int
> >>>    rte_eth_dev_pool_ops_supported(uint16_t port_id, const char *pool)
> >>>    {
> >>>           struct rte_eth_dev *dev;
> >>> diff --git a/lib/librte_ethdev/rte_ethdev.h 
> >>> b/lib/librte_ethdev/rte_ethdev.h
> >>> index d937fb4..29dcfea 100644
> >>> --- a/lib/librte_ethdev/rte_ethdev.h
> >>> +++ b/lib/librte_ethdev/rte_ethdev.h
> >>> @@ -804,6 +804,46 @@ struct rte_eth_txconf {
> >>>    };
> >>>
> >>>    /**
> >>> + * @warning
> >>> + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> >> notice
> >>> + *
> >>> + * A structure used to return the hairpin capabilities that are supportd.
> >> supportd -> supported
> >>
> > Will fix.
> >
> >>> + */
> >>> +struct rte_eth_hairpin_cap {
> >>> + int16_t max_n_queues;
> >>> + /**< The max number of hairpin queuesi. -1 no limit. */
> >> I'm not sure that I like type difference from max_rx_queues here.
> >> I think it would be better to use uint16_t. I would say there is point
> >> to highlight no limit (first of all I'm not sure that it makes sense,
> >> second, UINT16_MAX will obviously do the job in uint16_t.
> >>
> >> Is it both Rx and Tx?
> >>
> >>> + int16_t max_rx_2_tx;
> >>> + /**< Max number of Rx queues to be connected to one Tx queue. */
> >>> + int16_t max_tx_2_rx;
> >>> + /**< Max number of Tx queues to be connected to one Rx queue. */
> >> I would prefer to have uint16_t here as well. Mainly for consistency.
> >>
> > Agree, will fix,
> >
> >>> + uint16_t max_nb_desc; /**< The max num of descriptors. */
> >> Is it common for Rx and Tx? What about min?
> >>
> > I think min is always 1, by  definition.
> 
> OK
> 
> >>> +};
> >>> +
> >>> +#define RTE_ETH_MAX_HAIRPIN_PEERS 32
> >>> +
> >>> +/**
> >>> + * @warning
> >>> + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> >> notice
> >>> + *
> >>> + * A structure used to hold hairpin peer data.
> >>> + */
> >>> +struct rte_eth_hairpin_peer {
> >>> + uint16_t port; /**< Peer port. */
> >>> + uint16_t queue; /**< Peer queue. */
> >>> +};
> >>> +
> >>> +/**
> >>> + * @warning
> >>> + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> >> notice
> >>> + *
> >>> + * A structure used to configure hairpin binding.
> >> It should be explained what happens if Rx queue has many Tx queues.
> >> Is packet duplicated? Or distributed?
> >>
> > Like we said before, I don't know it depends on the Nic.
> > In case of Mellanox we don't support 1 to many.
> 
> I see, but what application should expect?

I think that when some Nic supports such connection, it should add in the 
capabilities 
or in documentation the expected results. 
Personally I think that the common use case will be distributed (RSS on the Tx) 
but it is only 
my personal thinking, your question will be answered when someone will 
implement it.
 
> 
> >>> + */
> >>> +struct rte_eth_hairpin_conf {
> >>> + uint16_t peer_n; /**< The number of peers. */
> >>> + struct rte_eth_hairpin_peer peers[RTE_ETH_MAX_HAIRPIN_PEERS];
> >>> +};
> >>> +
> >>> +/**
> >>>     * A structure contains information about HW descriptor ring 
> >>> limitations.
> >>>     */
> >>>    struct rte_eth_desc_lim {
> >>> @@ -1080,6 +1120,8 @@ struct rte_eth_conf {
> >>>    /**< Device supports Rx queue setup after device started*/
> >>>    #define RTE_ETH_DEV_CAPA_RUNTIME_TX_QUEUE_SETUP 0x00000002
> >>>    /**< Device supports Tx queue setup after device started*/
> >>> +#define RTE_ETH_DEV_CAPA_HAIRPIN_SUPPORT 0x00000004
> >>> +/**< Device supports hairpin queues. */
> >> Do we really need it? Isn't rte_eth_dev_hairpin_capability_get() returning
> >> -ENOTSUP sufficient?
> >>
> > I agree with you, but my thinking was that using the cap the application
> > can avoid calling to function that will fail.
> > If you approve I will remove this cap.
> 
> Runtime setup flags are required since these functions are always
> supported, but it is not alway possible to use these function when
> device is started. In this case I think there is no necessity to add
> the capability since we have no similar caps for anything else.
> 

O.K. will remove it.

> >>>    /*
> >>>     * If new Tx offload capabilities are defined, they also must be
> >>> @@ -1277,6 +1319,7 @@ struct rte_eth_dcb_info {
> >>>     */
> >>>    #define RTE_ETH_QUEUE_STATE_STOPPED 0
> >>>    #define RTE_ETH_QUEUE_STATE_STARTED 1
> >>> +#define RTE_ETH_QUEUE_STATE_HAIRPIN 2
> >>>
> >>>    #define RTE_ETH_ALL RTE_MAX_ETHPORTS
> >>>
> >>> @@ -1771,6 +1814,34 @@ int rte_eth_rx_queue_setup(uint16_t port_id,
> >> uint16_t rx_queue_id,
> >>>                   struct rte_mempool *mb_pool);
> >>>
> >>>    /**
> >>> + * @warning
> >>> + * @b EXPERIMENTAL: this API may change, or be removed, without prior
> >> notice
> >>> + *
> >>> + * Allocate and set up a hairpin receive queue for an Ethernet device.
> >>> + *
> >>> + * The function set up the selected queue to be used in hairpin.
> >>> + *
> >>> + * @param port_id
> >>> + *   The port identifier of the Ethernet device.
> >>> + * @param rx_queue_id
> >>> + *   The index of the receive queue to set up.
> >>> + *   The value must be in the range [0, nb_rx_queue - 1] previously
> supplied
> >>> + *   to rte_eth_dev_configure().
> >>> + * @param nb_rx_desc
> >>> + *   The number of receive descriptors to allocate for the receive ring.
> >> Is it allows to specify 0 to pick driver recommended value?
> >>
> > Yes, (assuming you are talking about the nb_rx_desc)
> 
> Please, highlight it in the description.
> 

O.K.

[nip]

Thanks,
Ori

Reply via email to