|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Minios-devel] [UNIKRAFT PATCH v3 2/4] lib/uknetdev: Flag-based status report on rx and tx functions
> On 31. Jan 2019, at 14:48, Sharan Santhanam <Sharan.Santhanam@xxxxxxxxx>
> wrote:
>
> Hello Simon,
>
> Please find the comments inline.
>
> Thanks & Regards
> Sharan
>
> On 1/31/19 1:04 AM, Simon Kuenzer wrote:
>> Introduce flag based status return codes on receive and transmit
>> functions. They are replacing the current enum-like return codes. The
>> flags are able to inform the API user about additional driver
>> states (e.g., queue underruns).
>> Signed-off-by: Simon Kuenzer <simon.kuenzer@xxxxxxxxx>
>> ---
>> lib/uknetdev/include/uk/netdev.h | 107 ++++++++++++++++++++++----
>> lib/uknetdev/include/uk/netdev_core.h | 11 +++
>> plat/drivers/virtio/virtio_net.c | 91 +++++++++++++---------
>> 3 files changed, 158 insertions(+), 51 deletions(-)
>> diff --git a/lib/uknetdev/include/uk/netdev.h
>> b/lib/uknetdev/include/uk/netdev.h
>> index 18878400..88b89135 100644
>> --- a/lib/uknetdev/include/uk/netdev.h
>> +++ b/lib/uknetdev/include/uk/netdev.h
>> @@ -438,12 +438,18 @@ static inline int uk_netdev_rxq_intr_disable(struct
>> uk_netdev *dev,
>> * Reference to netbuf pointer which will be point to the received packet
>> * after the function call. `pkt` has never to be `NULL`.
>> * @return
>> - * - (0): No packet available
>> - * - (1): `pkt` points to received netbuf
>> - * - (2): `pkt` points to received netbuf but more received packets are
>> - * available on the receive queue. When interrupts are used, they
>> are
>> - * disabled until 1 is returned on subsequent calls
>> - * - (<0): Error code from driver
>> + * - (>=0): Positive value with status flags
>> + * - UK_NETDEV_STATUS_SUCCESS: `pkt` points to received netbuf. Whenever
>> + * this flag is not set, there was no packet received.
>> + * - UK_NETDEV_STATUS_MORE: Indicates that more received packets are
>> + * available on the receive queue. When interrupts are used, they are
>> + * disabled until this flag is unset by a subsequent call.
>> + * This flag may only be set together with UK_NETDEV_STATUS_SUCCESS.
>> + * - UK_NETDEV_STATUS_UNDERRUN: Informs that some available slots of the
>> + * receive queue could not be programmed with a receive buffer. The
>> + * user-provided receive buffer allocator function returned with an
>> error
>> + * (e.g., out of memory).
>> + * - (<0): Negative value with error code from driver, no packet is
>> returned.
>> */
>> static inline int uk_netdev_rx_one(struct uk_netdev *dev, uint16_t queue_id,
>> struct uk_netbuf **pkt)
>> @@ -474,13 +480,15 @@ static inline int uk_netdev_rx_one(struct uk_netdev
>> *dev, uint16_t queue_id,
>> * for doing a transmission - inspect `nb_encap` with
>> uk_netdev_info_get().
>> * `pkt` has never to be `NULL`.
>> * @return
>> - * - (0): No space left on transmit queue, `pkt` is not sent
>> - * - (1): `pkt` was successfully put to the transmit queue,
>> - * queue is currently full
>> - * - (2): `pkt` was successfully put to the transmit queue,
>> - * there is still at least one descriptor available for a
>> - * subsequent transmission
>> - * - (<0): Error code from driver, `pkt` is not sent
>> + * - (>=0): Positive value with status flags
>> + * - UK_NETDEV_STATUS_SUCCESS: `pkt` was successfully put to the
>> transmit
>> + * queue. Whenever this flag is not set, there was no space left on
>> the
>> + * transmit queue to send `pkt`.
>> + * - UK_NETDEV_STATUS_MORE: Indicates there is still at least one
>> descriptor
>> + * available for a subsequent transmission. If the flag is unset
>> means
>> + * that the transmit queue is full.
>> + * This flag may only be set together with UK_NETDEV_STATUS_SUCCESS.
>> + * - (<0): Negative value with error code from driver, no packet was sent.
>> */
>> static inline int uk_netdev_tx_one(struct uk_netdev *dev, uint16_t queue_id,
>> struct uk_netbuf *pkt)
>> @@ -495,6 +503,79 @@ static inline int uk_netdev_tx_one(struct uk_netdev
>> *dev, uint16_t queue_id,
>> return dev->tx_one(dev, dev->_tx_queue[queue_id], pkt);
>> }
>> +/**
>> + * Tests for status flags returned by `uk_netdev_rx_one` or
>> `uk_netdev_tx_one`.
>> + * When the functions returned an error code or one of the selected flags is
>> + * unset, this macro returns False.
>> + *
>> + * @param status
>> + * Return status (int)
>> + * @param flag
>> + * Flag(s) to test
>> + * @return
>> + * - (True): All flags are set and status is not negative
>> + * - (False): At least one flag is not set or status is negative
>> + */
>> +#define uk_netdev_status_test_set(status, flag) \
>> + (((int)(status) & ((int)(flag) | INT_MIN)) == (flag))
>> +
>> +/**
>> + * Tests for unset status flags returned by `uk_netdev_rx_one` or
>> + * `uk_netdev_tx_one`. When the functions returned an error code orDuring
>> Underrun, we will notify the host of the buffer we filled in.
> T one of the
>> + * selected the flags is set, this macro returns False.
>> + *
>> + * @param status
>> + * Return status (int)
>> + * @param flag
>> + * Flag(s) to test
>> + * @return
>> + * - (True): Flags are not set and status is not negative
>> + * - (False): At least one flag is set or status is negative
>> + */
>> +#define uk_netdev_status_test_unset(status, flag) \
>> + (((int)(status) & ((int)(flag) | INT_MIN)) == (0x0))
>> +
>> +/**
>> + * Tests if the return status of `uk_netdev_rx_one` or `uk_netdev_tx_one`
>> + * indicates a successful operation (e.g., packet sent or received).
>> + *
>> + * @param status
>> + * Return status (int)
>> + * @return
>> + * - (True): Operation was successful
>> + * - (False): Operation was unsuccessful or error happend
>> + */
>> +#define uk_netdev_status_successful(status) \
>> + uk_netdev_status_test_set((status), UK_NETDEV_STATUS_SUCCESS)
>> +
>> +/**
>> + * Tests if the return status of `uk_netdev_rx_one` or `uk_netdev_tx_one`
>> + * indicates that the operation should be retried (e.g., packet sent or
>> + * received).
>> + *
>> + * @param status
>> + * Return status (int)
>> + * @return
>> + * - (True): Operation should be retried
>> + * - (False): Operation was successful or error happened
>> + */
>> +#define uk_netdev_status_notready(status) \
>> + uk_netdev_status_test_unset((status), UK_NETDEV_STATUS_SUCCESS)
>> +
>> +/**
>> + * Tests if the return status of `uk_netdev_rx_one` or `uk_netdev_tx_one`
>> + * indicates that the last operation can be successfully repeatet again.
>> + *
>> + * @param status
>> + * Return status (int)
>> + * @return
>> + * - (True): Flag UK_NETDEV_STATUS_MORE is set
>> + * - (False): Operation was successful or error happened
>> + */
>> +#define uk_netdev_status_more(status)
>> \
>> + uk_netdev_status_test_set((status), (UK_NETDEV_STATUS_SUCCESS \
>> + | UK_NETDEV_STATUS_MORE))
>> +
>> #ifdef __cplusplus
>> }
>> #endif
>> diff --git a/lib/uknetdev/include/uk/netdev_core.h
>> b/lib/uknetdev/include/uk/netdev_core.h
>> index d30886de..f877f1e7 100644
>> --- a/lib/uknetdev/include/uk/netdev_core.h
>> +++ b/lib/uknetdev/include/uk/netdev_core.h
>> @@ -285,6 +285,17 @@ typedef int (*uk_netdev_rxq_intr_enable_t)(struct
>> uk_netdev *dev,
>> typedef int (*uk_netdev_rxq_intr_disable_t)(struct uk_netdev *dev,
>> struct uk_netdev_rx_queue *queue);
>> +/**
>> + * Status code flags returned by rx and tx functions
>> + */
>> +/** Successful operation (packet received or transmitted). */
>> +#define UK_NETDEV_STATUS_SUCCESS (0x1)
>> +/** More room available for operation (e.g., still space on queue for
>> sending
>> + or more packets available on receive queue */
>> +#define UK_NETDEV_STATUS_MORE (0x2)
>> +/** Queue underrun (e.g., out-of-memory when allocating new receive
>> buffers). */
>> +#define UK_NETDEV_STATUS_UNDERRUN (0x4)
>> +
>> /** Driver callback type to retrieve one packet from a RX queue. */
>> typedef int (*uk_netdev_rx_one_t)(struct uk_netdev *dev,
>> struct uk_netdev_rx_queue *queue,
>> diff --git a/plat/drivers/virtio/virtio_net.c
>> b/plat/drivers/virtio/virtio_net.c
>> index 24ef63b0..cb771efe 100644
>> --- a/plat/drivers/virtio/virtio_net.c
>> +++ b/plat/drivers/virtio/virtio_net.c
>> @@ -213,8 +213,8 @@ static int virtio_netdev_rxq_dequeue(struct
>> uk_netdev_rx_queue *rxq,
>> static int virtio_netdev_rxq_enqueue(struct uk_netdev_rx_queue *rxq,
>> struct uk_netbuf *netbuf);
>> static int virtio_netdev_recv_done(struct virtqueue *vq, void *priv);
>> -static void virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq,
>> - __u16 num, int notify);
>> +static int virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq,
>> + __u16 num, int notify);
>> /**
>> * Static global constants
>> @@ -268,12 +268,13 @@ static void virtio_netdev_xmit_free(struct
>> uk_netdev_tx_queue *txq)
>> #define RX_FILLUP_BATCHLEN 64
>> -static void virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq,
>> - __u16 nb_desc,
>> - int notify)
>> +static int virtio_netdev_rx_fillup(struct uk_netdev_rx_queue *rxq,
>> + __u16 nb_desc,
>> + int notify)
>> {
>> struct uk_netbuf *netbuf[RX_FILLUP_BATCHLEN];
>> int rc = 0;
>> + int status = 0x0;
>> __u16 i, j;
>> __u16 req;
>> __u16 cnt = 0;
>> @@ -305,7 +306,8 @@ static void virtio_netdev_rx_fillup(struct
>> uk_netdev_rx_queue *rxq,
>> */
>> for (j = i; j < cnt; j++)
>> uk_netbuf_free(netbuf[j]);
>> - return;
>> + status |= UK_NETDEV_STATUS_UNDERRUN;
>> + return status;
> During Underrun, we will notify the host of the buffer we filled in.
> This has to be "goto out:" instead of return status.
Yes, sorry. It also happened in the previous patch. I will change both. Thanks!
>
>> }
>> filled += 2;
>> }
>> @@ -313,6 +315,7 @@ static void virtio_netdev_rx_fillup(struct
>> uk_netdev_rx_queue *rxq,
>> if (unlikely(cnt < req)) {
>> uk_pr_debug("Incomplete fill-up of netbufs on receive
>> virtqueue %p: Out of memory",
>> rxq);
>> + status |= UK_NETDEV_STATUS_UNDERRUN;
>> goto out;
>> }
>> }
>> @@ -326,6 +329,8 @@ out:
>> */
>> if (notify && filled)
>> virtqueue_host_notify(rxq->vq);
>> +
>> + return status;
>> }
>> static int virtio_netdev_xmit(struct uk_netdev *dev,
>> @@ -337,6 +342,7 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
>> struct virtio_net_hdr_padded *padded_hdr;
>> int16_t header_sz = sizeof(*padded_hdr);
>> int rc = 0;
>> + int status = 0x0;
>> size_t total_len = 0;
>> __u8 *buf_start;
>> size_t buf_len;
>> @@ -361,7 +367,7 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
>> if (unlikely(rc != 1)) {
>> uk_pr_err("Failed to prepend virtio header\n");
>> rc = -ENOSPC;
>> - goto exit;
>> + goto err_exit;
>> }
>> vhdr = pkt->data;
>> @@ -388,18 +394,18 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
>> rc = uk_sglist_append(&queue->sg, vhdr, sizeof(*vhdr));
>> if (unlikely(rc != 0)) {
>> uk_pr_err("Failed to append to the sg list\n");
>> - goto exit;
>> + goto err_remove_vhdr;
>> }
>> rc = uk_sglist_append(&queue->sg, buf_start, buf_len);
>> if (unlikely(rc != 0)) {
>> uk_pr_err("Failed to append to the sg list\n");
>> - goto exit;
>> + goto err_remove_vhdr;
>> }
>> if (pkt->next) {
>> rc = uk_sglist_append_netbuf(&queue->sg, pkt->next);
>> if (unlikely(rc != 0)) {
>> uk_pr_err("Failed to append to the sg list\n");
>> - goto exit;
>> + goto err_remove_vhdr;
>> }
>> }
>> @@ -408,7 +414,7 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
>> uk_pr_err("Packet size too big: %lu, max:%u\n",
>> total_len, VIRTIO_PKT_BUFFER_LEN);
>> rc = -ENOTSUP;
>> - goto remove_vhdr;
>> + goto err_remove_vhdr;
>> }
>> /**
>> @@ -417,31 +423,34 @@ static int virtio_netdev_xmit(struct uk_netdev *dev,
>> rc = virtqueue_buffer_enqueue(queue->vq, pkt, &queue->sg,
>> queue->sg.sg_nseg, 0);
>> if (likely(rc >= 0)) {
>> + status |= UK_NETDEV_STATUS_SUCCESS;
>> /**
>> * Notify the host the new buffer.
>> */
>> virtqueue_host_notify(queue->vq);
>> /**
>> * When there is further space available in the ring
>> - * return 2 else 1.
>> + * return UK_NETDEV_STATUS_MORE.
>> */
>> - rc = likely(rc > 0) ? 2 : 1;
>> + status |= likely(rc > 0) ? UK_NETDEV_STATUS_MORE : 0x0;
>> } else if (rc == -ENOSPC) {
>> uk_pr_debug("No more descriptor available\n");
>> - rc = 0;
>> - goto remove_vhdr;
>> + /**
>> + * Remove header before exiting because we could not send
>> + */
>> + uk_netbuf_header(pkt, -header_sz);
>> } else {
>> uk_pr_err("Failed to enqueue descriptors into the ring: %d\n",
>> rc);
>> - goto remove_vhdr;
>> + goto err_remove_vhdr;
>> }
>> + return status;
>> -exit:
>> - return rc;
>> -
>> -remove_vhdr:
>> +err_remove_vhdr:
>> uk_netbuf_header(pkt, -header_sz);
>> - goto exit;
>> +err_exit:
>> + UK_ASSERT(rc < 0);
>> + return rc;
>> }
>> static int virtio_netdev_rxq_enqueue(struct uk_netdev_rx_queue *rxq,
>> @@ -529,8 +538,8 @@ static int virtio_netdev_recv(struct uk_netdev *dev,
>> struct uk_netdev_rx_queue *queue,
>> struct uk_netbuf **pkt)
>> {
>> + int status = 0x0;
>> int rc = 0;
>> - int cnt = 0;
>> UK_ASSERT(dev && queue);
>> UK_ASSERT(pkt);
>> @@ -545,14 +554,14 @@ static int virtio_netdev_recv(struct uk_netdev *dev,
>> uk_pr_err("Failed to dequeue the packet: %d\n", rc);
>> goto err_exit;
>> }
>> - cnt = (*pkt) ? 1 : 0;
>> - virtio_netdev_rx_fillup(queue, (queue->nb_desc - rc), 1);
>> + status |= (*pkt) ? UK_NETDEV_STATUS_SUCCESS : 0x0;
>> + status |= virtio_netdev_rx_fillup(queue, (queue->nb_desc - rc), 1);
>> /* Enable interrupt only when user had previously enabled it */
>> if (queue->intr_enabled & VTNET_INTR_USR_EN_MASK) {
>> /* Need to enable the interrupt on the last packet */
>> rc = virtqueue_intr_enable(queue->vq);
>> - if (rc == 1 && cnt == 0) {
>> + if (rc == 1 && !(*pkt)) {
>> /**
>> * Packet arrive after reading the queue and before
>> * enabling the interrupt
>> @@ -563,29 +572,35 @@ static int virtio_netdev_recv(struct uk_netdev *dev,
>> rc);
>> goto err_exit;
>> }
>> + status |= UK_NETDEV_STATUS_SUCCESS;
>> +
>> /* Need to enable the interrupt on the last packet */
>> rc = virtqueue_intr_enable(queue->vq);
>> - cnt = (rc == 1) ? 2 : 1;
>> - /* Since we received something, we need to fillup */
>> - virtio_netdev_rx_fillup(queue, (queue->nb_desc - rc),
>> 1);
>> - } else if (cnt > 0) {
>> - /* When there is packet in the buffer */
>> - cnt = (rc == 1) ? 2 : 1;
>> + status |= (rc == 1) ? UK_NETDEV_STATUS_MORE : 0x0;
>> +
>> + /*
>> + * Since we received something, we need to fillup
>> + * and notify
>> + */
>> + status |= virtio_netdev_rx_fillup(queue,
>> + (queue->nb_desc - rc),
>> + 1);
>> + } else if (*pkt) {
>> + /* When we originally got a packet and there is more */
>> + status |= (rc == 1) ? UK_NETDEV_STATUS_MORE : 0x0;
>> }
>> - } else if (cnt > 0) {
>> + } else if (*pkt) {
>> /**
>> * For polling case, we report always there are further
>> * packets unless the queue is empty.
>> */
>> - cnt = 2;
>> + status |= UK_NETDEV_STATUS_MORE;
>> }
>> -
>> -exit:
>> - return cnt;
>> + return status;
>> err_exit:
>> - cnt = rc;
>> - goto exit;
>> + UK_ASSERT(rc < 0);
>> + return rc;
>> }
>> static struct uk_netdev_rx_queue *virtio_netdev_rx_queue_setup(
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |